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