Home | History | Annotate | Download | only in JAJP
      1 /*
      2  * Copyright (C) 2008,2009  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 
     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 
    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 
    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 
    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 
    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 
    196         void hide() {
    197             if (window.isShowing()) {
    198                 textView.setOnTouchListener(null);
    199                 window.dismiss();
    200             }
    201         }
    202 
    203         boolean isShowing() {
    204             return window.isShowing();
    205         }
    206     }
    207 
    208     /** Constructor */
    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 
    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 
    325     public void start() {
    326         mInputView.getLocationInWindow(mLocation);
    327         mBubbleIndex = -1;
    328         mInputView.setOnTouchListener(this);
    329         next();
    330     }
    331 
    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 
    364     void hide() {
    365         for (int i = 0; i < mBubbles.size(); i++) {
    366             mBubbles.get(i).hide();
    367         }
    368         mInputView.setOnTouchListener(null);
    369     }
    370 
    371     public boolean close() {
    372         mHandler.removeMessages(MSG_SHOW_BUBBLE);
    373         hide();
    374         return true;
    375     }
    376 
    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