Home | History | Annotate | Download | only in latin
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
      5  * use this file except in compliance with the License. You may obtain a copy of
      6  * 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, WITHOUT
     12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     13  * License for the specific language governing permissions and limitations under
     14  * the License.
     15  */
     16 
     17 package com.android.inputmethod.latin;
     18 
     19 import android.content.Context;
     20 import android.graphics.drawable.Drawable;
     21 import android.os.Handler;
     22 import android.os.Message;
     23 import android.text.Layout;
     24 import android.text.SpannableStringBuilder;
     25 import android.text.StaticLayout;
     26 import android.view.Gravity;
     27 import android.view.LayoutInflater;
     28 import android.view.MotionEvent;
     29 import android.view.View;
     30 import android.view.View.OnTouchListener;
     31 import android.widget.PopupWindow;
     32 import android.widget.TextView;
     33 
     34 import java.util.ArrayList;
     35 import java.util.List;
     36 
     37 public class Tutorial implements OnTouchListener {
     38 
     39     private List<Bubble> mBubbles = new ArrayList<Bubble>();
     40     private View mInputView;
     41     private LatinIME mIme;
     42     private int[] mLocation = new int[2];
     43 
     44     private static final int MSG_SHOW_BUBBLE = 0;
     45 
     46     private int mBubbleIndex;
     47 
     48     Handler mHandler = new Handler() {
     49         @Override
     50         public void handleMessage(Message msg) {
     51             switch (msg.what) {
     52                 case MSG_SHOW_BUBBLE:
     53                     Bubble bubba = (Bubble) msg.obj;
     54                     bubba.show(mLocation[0], mLocation[1]);
     55                     break;
     56             }
     57         }
     58     };
     59 
     60     class Bubble {
     61         Drawable bubbleBackground;
     62         int x;
     63         int y;
     64         int width;
     65         int gravity;
     66         CharSequence text;
     67         boolean dismissOnTouch;
     68         boolean dismissOnClose;
     69         PopupWindow window;
     70         TextView textView;
     71         View inputView;
     72 
     73         Bubble(Context context, View inputView,
     74                 int backgroundResource, int bx, int by, int textResource1, int textResource2) {
     75             bubbleBackground = context.getResources().getDrawable(backgroundResource);
     76             x = bx;
     77             y = by;
     78             width = (int) (inputView.getWidth() * 0.9);
     79             this.gravity = Gravity.TOP | Gravity.LEFT;
     80             text = new SpannableStringBuilder()
     81                 .append(context.getResources().getText(textResource1))
     82                 .append("\n")
     83                 .append(context.getResources().getText(textResource2));
     84             this.dismissOnTouch = true;
     85             this.dismissOnClose = false;
     86             this.inputView = inputView;
     87             window = new PopupWindow(context);
     88             window.setBackgroundDrawable(null);
     89             LayoutInflater inflate =
     90                 (LayoutInflater) context
     91                         .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
     92             textView = (TextView) inflate.inflate(R.layout.bubble_text, null);
     93             textView.setBackgroundDrawable(bubbleBackground);
     94             textView.setText(text);
     95             //textView.setText(textResource1);
     96             window.setContentView(textView);
     97             window.setFocusable(false);
     98             window.setTouchable(true);
     99             window.setOutsideTouchable(false);
    100         }
    101 
    102         private int chooseSize(PopupWindow pop, View parentView, CharSequence text, TextView tv) {
    103             int wid = tv.getPaddingLeft() + tv.getPaddingRight();
    104             int ht = tv.getPaddingTop() + tv.getPaddingBottom();
    105 
    106             /*
    107              * Figure out how big the text would be if we laid it out to the
    108              * full width of this view minus the border.
    109              */
    110             int cap = width - wid;
    111 
    112             Layout l = new StaticLayout(text, tv.getPaint(), cap,
    113                                         Layout.Alignment.ALIGN_NORMAL, 1, 0, true);
    114             float max = 0;
    115             for (int i = 0; i < l.getLineCount(); i++) {
    116                 max = Math.max(max, l.getLineWidth(i));
    117             }
    118 
    119             /*
    120              * Now set the popup size to be big enough for the text plus the border.
    121              */
    122             pop.setWidth(width);
    123             pop.setHeight(ht + l.getHeight());
    124             return l.getHeight();
    125         }
    126 
    127         void show(int offx, int offy) {
    128             int textHeight = chooseSize(window, inputView, text, textView);
    129             offy -= textView.getPaddingTop() + textHeight;
    130             if (inputView.getVisibility() == View.VISIBLE
    131                     && inputView.getWindowVisibility() == View.VISIBLE) {
    132                 try {
    133                     if ((gravity & Gravity.BOTTOM) == Gravity.BOTTOM) offy -= window.getHeight();
    134                     if ((gravity & Gravity.RIGHT) == Gravity.RIGHT) offx -= window.getWidth();
    135                     textView.setOnTouchListener(new View.OnTouchListener() {
    136                         public boolean onTouch(View view, MotionEvent me) {
    137                             Tutorial.this.next();
    138                             return true;
    139                         }
    140                     });
    141                     window.showAtLocation(inputView, Gravity.NO_GRAVITY, x + offx, y + offy);
    142                 } catch (Exception e) {
    143                     // Input view is not valid
    144                 }
    145             }
    146         }
    147 
    148         void hide() {
    149             if (window.isShowing()) {
    150                 textView.setOnTouchListener(null);
    151                 window.dismiss();
    152             }
    153         }
    154 
    155         boolean isShowing() {
    156             return window.isShowing();
    157         }
    158     }
    159 
    160     public Tutorial(LatinIME ime, LatinKeyboardView inputView) {
    161         Context context = inputView.getContext();
    162         mIme = ime;
    163         int inputWidth = inputView.getWidth();
    164         final int x = inputWidth / 20; // Half of 1/10th
    165         Bubble bWelcome = new Bubble(context, inputView,
    166                 R.drawable.dialog_bubble_step02, x, 0,
    167                 R.string.tip_to_open_keyboard, R.string.touch_to_continue);
    168         mBubbles.add(bWelcome);
    169         Bubble bAccents = new Bubble(context, inputView,
    170                 R.drawable.dialog_bubble_step02, x, 0,
    171                 R.string.tip_to_view_accents, R.string.touch_to_continue);
    172         mBubbles.add(bAccents);
    173         Bubble b123 = new Bubble(context, inputView,
    174                 R.drawable.dialog_bubble_step07, x, 0,
    175                 R.string.tip_to_open_symbols, R.string.touch_to_continue);
    176         mBubbles.add(b123);
    177         Bubble bABC = new Bubble(context, inputView,
    178                 R.drawable.dialog_bubble_step07, x, 0,
    179                 R.string.tip_to_close_symbols, R.string.touch_to_continue);
    180         mBubbles.add(bABC);
    181         Bubble bSettings = new Bubble(context, inputView,
    182                 R.drawable.dialog_bubble_step07, x, 0,
    183                 R.string.tip_to_launch_settings, R.string.touch_to_continue);
    184         mBubbles.add(bSettings);
    185         Bubble bDone = new Bubble(context, inputView,
    186                 R.drawable.dialog_bubble_step02, x, 0,
    187                 R.string.tip_to_start_typing, R.string.touch_to_finish);
    188         mBubbles.add(bDone);
    189         mInputView = inputView;
    190     }
    191 
    192     void start() {
    193         mInputView.getLocationInWindow(mLocation);
    194         mBubbleIndex = -1;
    195         mInputView.setOnTouchListener(this);
    196         next();
    197     }
    198 
    199     boolean next() {
    200         if (mBubbleIndex >= 0) {
    201             // If the bubble is not yet showing, don't move to the next.
    202             if (!mBubbles.get(mBubbleIndex).isShowing()) {
    203                 return true;
    204             }
    205             // Hide all previous bubbles as well, as they may have had a delayed show
    206             for (int i = 0; i <= mBubbleIndex; i++) {
    207                 mBubbles.get(i).hide();
    208             }
    209         }
    210         mBubbleIndex++;
    211         if (mBubbleIndex >= mBubbles.size()) {
    212             mInputView.setOnTouchListener(null);
    213             mIme.sendDownUpKeyEvents(-1); // Inform the setupwizard that tutorial is in last bubble
    214             mIme.tutorialDone();
    215             return false;
    216         }
    217         if (mBubbleIndex == 3 || mBubbleIndex == 4) {
    218             mIme.mKeyboardSwitcher.toggleSymbols();
    219         }
    220         mHandler.sendMessageDelayed(
    221                 mHandler.obtainMessage(MSG_SHOW_BUBBLE, mBubbles.get(mBubbleIndex)), 500);
    222         return true;
    223     }
    224 
    225     void hide() {
    226         for (int i = 0; i < mBubbles.size(); i++) {
    227             mBubbles.get(i).hide();
    228         }
    229         mInputView.setOnTouchListener(null);
    230     }
    231 
    232     boolean close() {
    233         mHandler.removeMessages(MSG_SHOW_BUBBLE);
    234         hide();
    235         return true;
    236     }
    237 
    238     public boolean onTouch(View v, MotionEvent event) {
    239         if (event.getAction() == MotionEvent.ACTION_DOWN) {
    240             next();
    241         }
    242         return true;
    243     }
    244 }
    245