Home | History | Annotate | Download | only in EN
      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.EN;
     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 TutorialEN implements OnTouchListener {
     59 
     60     private List<Bubble> mBubbles = new ArrayList<Bubble>();
     61     private View mInputView;
     62     private OpenWnnEN mIme;
     63     private int[] mLocation = new int[2];
     64     private static final int MSG_SHOW_BUBBLE = 0;
     65 
     66     private int mBubbleIndex;
     67     private boolean mEnableKeyTouch = false;
     68 
     69     Handler mHandler = new Handler() {
     70         @Override
     71         public void handleMessage(Message msg) {
     72             switch (msg.what) {
     73                 case MSG_SHOW_BUBBLE:
     74                     Bubble bubba = (Bubble) msg.obj;
     75                     bubba.show(mLocation[0], mLocation[1]);
     76                     break;
     77             }
     78         }
     79     };
     80 
     81     class Bubble {
     82         Drawable bubbleBackground;
     83         int x;
     84         int y;
     85         int width;
     86         int gravity;
     87         CharSequence text;
     88         boolean dismissOnTouch;
     89         boolean dismissOnClose;
     90         PopupWindow window;
     91         TextView textView;
     92         View inputView;
     93 
     94         Bubble(Context context, View inputView,
     95                 int backgroundResource, int bx, int by, int description, int guide) {
     96 
     97             CharSequence text = context.getResources().getText(description);
     98             init(context, inputView, backgroundResource, bx, by, text, guide, false);
     99         }
    100 
    101         Bubble(Context context, View inputView, int backgroundResource, int bx, int by,
    102                CharSequence description, int guide, boolean leftAlign) {
    103             init(context, inputView, backgroundResource, bx, by, description, guide, leftAlign);
    104         }
    105 
    106         void init(Context context, View inputView, int backgroundResource,
    107                   int bx, int by, CharSequence description, int guide, boolean leftAlign) {
    108             bubbleBackground = context.getResources().getDrawable(backgroundResource);
    109             x = bx;
    110             y = by;
    111             width = (int) (inputView.getWidth() * 0.9);
    112             this.gravity = Gravity.TOP | Gravity.LEFT;
    113             text = new SpannableStringBuilder()
    114                 .append(description)
    115                 .append("\n")
    116                 .append(context.getResources().getText(guide));
    117             this.dismissOnTouch = true;
    118             this.dismissOnClose = false;
    119             this.inputView = inputView;
    120             window = new PopupWindow(context);
    121             window.setBackgroundDrawable(null);
    122             LayoutInflater inflate =
    123                 (LayoutInflater) context
    124                         .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    125             textView = (TextView) inflate.inflate(R.layout.bubble_text, null);
    126             textView.setBackgroundDrawable(bubbleBackground);
    127             textView.setText(text);
    128             if (leftAlign) {
    129                 textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
    130             }
    131             window.setContentView(textView);
    132             window.setFocusable(false);
    133             window.setTouchable(true);
    134             window.setOutsideTouchable(false);
    135         }
    136 
    137         private int chooseSize(PopupWindow pop, View parentView, CharSequence text, TextView tv) {
    138             int wid = tv.getPaddingLeft() + tv.getPaddingRight();
    139             int ht = tv.getPaddingTop() + tv.getPaddingBottom();
    140 
    141             /*
    142              * Figure out how big the text would be if we laid it out to the
    143              * full width of this view minus the border.
    144              */
    145             int cap = width - wid;
    146 
    147             Layout l = new StaticLayout(text, tv.getPaint(), cap,
    148                                         Layout.Alignment.ALIGN_NORMAL, 1, 0, true);
    149             float max = 0;
    150             for (int i = 0; i < l.getLineCount(); i++) {
    151                 max = Math.max(max, l.getLineWidth(i));
    152             }
    153 
    154             /*
    155              * Now set the popup size to be big enough for the text plus the border.
    156              */
    157             pop.setWidth(width);
    158             pop.setHeight(ht + l.getHeight());
    159             return l.getHeight();
    160         }
    161 
    162         void show(int offx, int offy) {
    163             int textHeight = chooseSize(window, inputView, text, textView);
    164             offy -= textView.getPaddingTop() + textHeight;
    165             if (inputView.getVisibility() == View.VISIBLE
    166                     && inputView.getWindowVisibility() == View.VISIBLE) {
    167                 try {
    168                     if ((gravity & Gravity.BOTTOM) == Gravity.BOTTOM) offy -= window.getHeight();
    169                     if ((gravity & Gravity.RIGHT) == Gravity.RIGHT) offx -= window.getWidth();
    170                     textView.setOnTouchListener(new View.OnTouchListener() {
    171                         public boolean onTouch(View view, MotionEvent me) {
    172                             boolean ret = !mEnableKeyTouch;
    173                             switch (me.getAction()) {
    174                             case MotionEvent.ACTION_UP:
    175                                 if (mBubbleIndex >= mBubbles.size()) {
    176                                     mInputView.setOnTouchListener(null);
    177                                 } else {
    178                                     TutorialEN.this.next();
    179                                 }
    180                                 break;
    181                             default:
    182                                 break;
    183                             }
    184                             return ret;
    185                         }
    186                     });
    187                     window.showAtLocation(inputView, Gravity.NO_GRAVITY, x + offx, y + offy);
    188                 } catch (Exception e) {
    189                 }
    190             }
    191         }
    192 
    193         void hide() {
    194             if (window.isShowing()) {
    195                 textView.setOnTouchListener(null);
    196                 window.dismiss();
    197             }
    198         }
    199 
    200         boolean isShowing() {
    201             return window.isShowing();
    202         }
    203     }
    204 
    205     /** Constructor */
    206     public TutorialEN(OpenWnnEN ime, View inputView, DefaultSoftKeyboardEN inputManager) {
    207         mInputView = inputView;
    208         mIme = ime;
    209 
    210         Context context = inputView.getContext();
    211         int inputWidth = inputView.getWidth();
    212         Resources r = inputView.getContext().getResources();
    213         final int x = inputWidth / 20;
    214         r.getDimensionPixelOffset(R.dimen.bubble_pointer_offset);
    215 
    216         SpannableStringBuilder spannable = new SpannableStringBuilder();
    217         Bubble button;
    218 
    219         spannable.clear();
    220         spannable.append(r.getText(R.string.tip_en_to_open_keyboard));
    221         button = new Bubble(context, inputView,
    222                 R.drawable.dialog_bubble, x, 0,
    223                 spannable, R.string.touch_to_continue, false);
    224         mBubbles.add(button);
    225 
    226         spannable.clear();
    227         spannable.append(r.getText(R.string.tip_en_to_close_keyboard));
    228 
    229         setSpan(spannable, "\u2190", R.drawable.tutorial_back);
    230 
    231         button = new Bubble(context, inputView,
    232                 R.drawable.dialog_bubble, x, 0,
    233                 spannable, R.string.touch_to_continue, false);
    234         mBubbles.add(button);
    235 
    236         button = new Bubble(context, inputView,
    237                 R.drawable.dialog_bubble, x, 0,
    238                 R.string.tip_en_end_of_tutorial, R.string.touch_to_finish);
    239         mBubbles.add(button);
    240     }
    241 
    242     private void setSpan(SpannableStringBuilder spannable, String marker, int imageResourceId) {
    243         String text = spannable.toString();
    244         int target = text.indexOf(marker);
    245         while (0 <= target) {
    246             ImageSpan span = new ImageSpan(mIme, imageResourceId,
    247                     DynamicDrawableSpan.ALIGN_BOTTOM);
    248             spannable.setSpan(span, target, target + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    249             target = text.indexOf(marker, target + 1);
    250         }
    251     }
    252 
    253     public void start() {
    254         mInputView.getLocationInWindow(mLocation);
    255         mBubbleIndex = -1;
    256         mInputView.setOnTouchListener(this);
    257         next();
    258     }
    259 
    260     boolean next() {
    261         if (mBubbleIndex >= 0) {
    262             if (!mBubbles.get(mBubbleIndex).isShowing()) {
    263                 return true;
    264             }
    265             for (int i = 0; i <= mBubbleIndex; i++) {
    266                 mBubbles.get(i).hide();
    267             }
    268         }
    269         mBubbleIndex++;
    270         if (mBubbleIndex >= mBubbles.size()) {
    271             mEnableKeyTouch = true;
    272             mIme.sendDownUpKeyEvents(-1);
    273             mIme.tutorialDone();
    274             return false;
    275         }
    276 
    277         mHandler.sendMessageDelayed(
    278                 mHandler.obtainMessage(MSG_SHOW_BUBBLE, mBubbles.get(mBubbleIndex)), 500);
    279         return true;
    280     }
    281 
    282     void hide() {
    283         for (int i = 0; i < mBubbles.size(); i++) {
    284             mBubbles.get(i).hide();
    285         }
    286         mInputView.setOnTouchListener(null);
    287     }
    288 
    289     public boolean close() {
    290         mHandler.removeMessages(MSG_SHOW_BUBBLE);
    291         hide();
    292         return true;
    293     }
    294 
    295     public boolean onTouch(View v, MotionEvent event) {
    296         boolean ret = !mEnableKeyTouch;
    297         if (event.getAction() == MotionEvent.ACTION_UP) {
    298             if (mBubbleIndex >= mBubbles.size()) {
    299                 mInputView.setOnTouchListener(null);
    300             }
    301         }
    302         return ret;
    303     }
    304 }
    305