• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008-2012  OMRON SOFTWARE Co., Ltd.
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 
17 /*
18  * Copyright (C) 2008-2009 Google Inc.
19  *
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
22  * the License at
23  *
24  * http://www.apache.org/licenses/LICENSE-2.0
25  *
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
30  * the License.
31  */
32 
33 package jp.co.omronsoft.openwnn.JAJP;
34 
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;
54 
55 import java.util.ArrayList;
56 import java.util.List;
57 
58 public class TutorialJAJP implements OnTouchListener {
59 
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;
66 
67     private int mBubbleIndex;
68     private DefaultSoftKeyboardJAJP mInputManager;
69     private boolean mEnableKeyTouch = false;
70 
71     Handler mHandler = new Handler() {
72         @Override
73         public void handleMessage(Message msg) {
74             switch (msg.what) {
75                 case MSG_SHOW_BUBBLE:
76                     Bubble bubba = (Bubble) msg.obj;
77                     bubba.show(mLocation[0], mLocation[1]);
78                     break;
79             }
80         }
81     };
82 
83     class Bubble {
84         Drawable bubbleBackground;
85         int x;
86         int y;
87         int width;
88         int gravity;
89         CharSequence text;
90         boolean dismissOnTouch;
91         boolean dismissOnClose;
92         PopupWindow window;
93         TextView textView;
94         View inputView;
95 
Bubble(Context context, View inputView, int backgroundResource, int bx, int by, int description, int guide)96         Bubble(Context context, View inputView,
97                 int backgroundResource, int bx, int by, int description, int guide) {
98 
99             CharSequence text = context.getResources().getText(description);
100             init(context, inputView, backgroundResource, bx, by, text, guide, false);
101         }
102 
Bubble(Context context, View inputView, int backgroundResource, int bx, int by, CharSequence description, int guide, boolean leftAlign)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);
106         }
107 
init(Context context, View inputView, int backgroundResource, int bx, int by, CharSequence description, int guide, boolean 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);
111             x = bx;
112             y = by;
113             width = (int) (inputView.getWidth() * 0.9);
114             this.gravity = Gravity.TOP | Gravity.LEFT;
115             text = new SpannableStringBuilder()
116                 .append(description)
117                 .append("\n")
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);
130             if (leftAlign) {
131                 textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
132             }
133             window.setContentView(textView);
134             window.setFocusable(false);
135             window.setTouchable(true);
136             window.setOutsideTouchable(false);
137         }
138 
chooseSize(PopupWindow pop, View parentView, CharSequence text, TextView tv)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();
142 
143             /*
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.
146              */
147             int cap = width - wid;
148 
149             Layout l = new StaticLayout(text, tv.getPaint(), cap,
150                                         Layout.Alignment.ALIGN_NORMAL, 1, 0, true);
151             float max = 0;
152             for (int i = 0; i < l.getLineCount(); i++) {
153                 max = Math.max(max, l.getLineWidth(i));
154             }
155 
156             /*
157              * Now set the popup size to be big enough for the text plus the border.
158              */
159             pop.setWidth(width);
160             pop.setHeight(ht + l.getHeight());
161             return l.getHeight();
162         }
163 
show(int offx, int offy)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) {
169                 try {
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) {
174 
175                             boolean ret = !mEnableKeyTouch;
176                             switch (me.getAction()) {
177                             case MotionEvent.ACTION_UP:
178                                 if (mBubbleIndex >= mBubbles.size()) {
179                                     mInputView.setOnTouchListener(null);
180                                 } else {
181                                     TutorialJAJP.this.next();
182                                 }
183                                 break;
184                             default:
185                                 break;
186                             }
187                             return ret;
188                         }
189                     });
190                     window.showAtLocation(inputView, Gravity.NO_GRAVITY, x + offx, y + offy);
191                 } catch (Exception e) {
192                 }
193             }
194         }
195 
hide()196         void hide() {
197             if (window.isShowing()) {
198                 textView.setOnTouchListener(null);
199                 window.dismiss();
200             }
201         }
202 
isShowing()203         boolean isShowing() {
204             return window.isShowing();
205         }
206     }
207 
208     /** Constructor */
TutorialJAJP(OpenWnnJAJP ime, View inputView, DefaultSoftKeyboardJAJP inputManager)209     public TutorialJAJP(OpenWnnJAJP ime, View inputView, DefaultSoftKeyboardJAJP inputManager) {
210         mInputManager = inputManager;
211         mInputView = inputView;
212         mIme = ime;
213 
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);
219 
220         SpannableStringBuilder spannable = new SpannableStringBuilder();
221         Bubble button;
222 
223         spannable.clear();
224         spannable.append(r.getText(R.string.tip_to_step1));
225 
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);
231 
232         spannable.clear();
233         spannable.append(r.getText(R.string.tip_to_step2_a));
234 
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);
240 
241         spannable.append(r.getText(R.string.tip_to_step2_b));
242 
243         setSpan(spannable, "\u2192", R.drawable.tutorial_12key_right);
244 
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);
249 
250         spannable.append(r.getText(R.string.tip_to_step2_c));
251 
252         setSpan(spannable, "\u25cb", R.drawable.tutorial_12key_toggle);
253 
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);
258 
259         spannable.append(r.getText(R.string.tip_to_step2_d));
260 
261         setSpan(spannable, "\u25a0", R.drawable.tutorial_12key_space_jp);
262 
263         setSpan(spannable, "\u2193", R.drawable.tutorial_12key_enter);
264 
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);
269 
270         spannable.clear();
271         spannable.append(r.getText(R.string.tip_to_step3_a));
272 
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);
278 
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);
283 
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);
288 
289         spannable.clear();
290         spannable.append(r.getText(R.string.tip_to_step4));
291 
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);
297 
298         spannable.clear();
299         spannable.append(r.getText(R.string.tip_to_step5));
300 
301         setSpan(spannable, "\u2190", R.drawable.tutorial_back);
302 
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);
307 
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);
312     }
313 
setSpan(SpannableStringBuilder spannable, String marker, int imageResourceId)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);
322         }
323     }
324 
start()325     public void start() {
326         mInputView.getLocationInWindow(mLocation);
327         mBubbleIndex = -1;
328         mInputView.setOnTouchListener(this);
329         next();
330     }
331 
next()332     boolean next() {
333         if (mBubbleIndex >= 0) {
334             if (!mBubbles.get(mBubbleIndex).isShowing()) {
335                 return true;
336             }
337             for (int i = 0; i <= mBubbleIndex; i++) {
338                 mBubbles.get(i).hide();
339             }
340         }
341         mBubbleIndex++;
342         if (mBubbleIndex >= mBubbles.size()) {
343             mEnableKeyTouch = true;
344             mIme.sendDownUpKeyEvents(-1);
345             mIme.tutorialDone();
346             return false;
347         }
348 
349         if ((6 <= mBubbleIndex) && (mBubbleIndex <= 8)) {
350             mInputManager.nextKeyMode();
351         }
352 
353         if (mBubbleIndex == LONG_PRESS_INDEX) {
354             mEnableKeyTouch = true;
355         } else if (LONG_PRESS_INDEX < mBubbleIndex) {
356             mEnableKeyTouch = false;
357         }
358 
359         mHandler.sendMessageDelayed(
360                 mHandler.obtainMessage(MSG_SHOW_BUBBLE, mBubbles.get(mBubbleIndex)), 500);
361         return true;
362     }
363 
hide()364     void hide() {
365         for (int i = 0; i < mBubbles.size(); i++) {
366             mBubbles.get(i).hide();
367         }
368         mInputView.setOnTouchListener(null);
369     }
370 
close()371     public boolean close() {
372         mHandler.removeMessages(MSG_SHOW_BUBBLE);
373         hide();
374         return true;
375     }
376 
onTouch(View v, MotionEvent event)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);
382             } else {
383                 if (mBubbleIndex != LONG_PRESS_INDEX) {
384                     next();
385                 }
386             }
387         }
388         return ret;
389     }
390 }
391