1e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa/* 259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Copyright (C) 2008-2012 OMRON SOFTWARE Co., Ltd. 3e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa * 4e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa * Licensed under the Apache License, Version 2.0 (the "License"); 5e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa * you may not use this file except in compliance with the License. 6e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa * You may obtain a copy of the License at 7e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa * 8e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa * http://www.apache.org/licenses/LICENSE-2.0 9e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa * 10e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa * Unless required by applicable law or agreed to in writing, software 11e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa * distributed under the License is distributed on an "AS IS" BASIS, 12e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa * See the License for the specific language governing permissions and 14e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa * limitations under the License. 15e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa */ 16e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 17e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa/* 18e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa * Copyright (C) 2008-2009 Google Inc. 19e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa * 20e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa * Licensed under the Apache License, Version 2.0 (the "License"); you may not 21e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa * use this file except in compliance with the License. You may obtain a copy of 22e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa * the License at 23e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa * 24e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa * http://www.apache.org/licenses/LICENSE-2.0 25e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa * 26e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa * Unless required by applicable law or agreed to in writing, software 27e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 28e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 29e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa * License for the specific language governing permissions and limitations under 30e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa * the License. 31e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa */ 32e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 33e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawapackage jp.co.omronsoft.openwnn.EN; 34e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 35e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawaimport jp.co.omronsoft.openwnn.*; 36e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawaimport android.content.Context; 37e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawaimport android.content.res.Resources; 38e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawaimport android.graphics.drawable.Drawable; 39e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawaimport android.os.Handler; 40e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawaimport android.os.Message; 41e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawaimport android.text.Layout; 42e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawaimport android.text.SpannableStringBuilder; 43e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawaimport android.text.StaticLayout; 44e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawaimport android.text.Spanned; 45e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawaimport android.text.style.ImageSpan; 46e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawaimport android.text.style.DynamicDrawableSpan; 47e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawaimport android.view.Gravity; 48e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawaimport android.view.LayoutInflater; 49e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawaimport android.view.MotionEvent; 50e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawaimport android.view.View; 51e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawaimport android.view.View.OnTouchListener; 52e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawaimport android.widget.PopupWindow; 53e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawaimport android.widget.TextView; 54e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 55e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawaimport java.util.ArrayList; 56e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawaimport java.util.List; 57e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 58e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawapublic class TutorialEN implements OnTouchListener { 59e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 60e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa private List<Bubble> mBubbles = new ArrayList<Bubble>(); 61e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa private View mInputView; 62e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa private OpenWnnEN mIme; 63e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa private int[] mLocation = new int[2]; 64e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa private static final int MSG_SHOW_BUBBLE = 0; 65e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 66e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa private int mBubbleIndex; 67e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa private boolean mEnableKeyTouch = false; 68e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 69e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa Handler mHandler = new Handler() { 70e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa @Override 71e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa public void handleMessage(Message msg) { 72e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa switch (msg.what) { 73e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa case MSG_SHOW_BUBBLE: 74e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa Bubble bubba = (Bubble) msg.obj; 75e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa bubba.show(mLocation[0], mLocation[1]); 76e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa break; 77e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 78e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 79e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa }; 80e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 81e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa class Bubble { 82e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa Drawable bubbleBackground; 83e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa int x; 84e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa int y; 85e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa int width; 86e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa int gravity; 87e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa CharSequence text; 88e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa boolean dismissOnTouch; 89e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa boolean dismissOnClose; 90e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa PopupWindow window; 91e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa TextView textView; 92e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa View inputView; 93e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 94e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa Bubble(Context context, View inputView, 95e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa int backgroundResource, int bx, int by, int description, int guide) { 96e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 97e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa CharSequence text = context.getResources().getText(description); 98e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa init(context, inputView, backgroundResource, bx, by, text, guide, false); 99e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 100e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 101e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa Bubble(Context context, View inputView, int backgroundResource, int bx, int by, 102e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa CharSequence description, int guide, boolean leftAlign) { 103e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa init(context, inputView, backgroundResource, bx, by, description, guide, leftAlign); 104e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 105e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 106e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa void init(Context context, View inputView, int backgroundResource, 107e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa int bx, int by, CharSequence description, int guide, boolean leftAlign) { 108e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa bubbleBackground = context.getResources().getDrawable(backgroundResource); 109e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa x = bx; 110e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa y = by; 111e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa width = (int) (inputView.getWidth() * 0.9); 112e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa this.gravity = Gravity.TOP | Gravity.LEFT; 113e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa text = new SpannableStringBuilder() 114e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa .append(description) 115e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa .append("\n") 116e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa .append(context.getResources().getText(guide)); 117e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa this.dismissOnTouch = true; 118e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa this.dismissOnClose = false; 119e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa this.inputView = inputView; 120e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa window = new PopupWindow(context); 121e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa window.setBackgroundDrawable(null); 122e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa LayoutInflater inflate = 123e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa (LayoutInflater) context 124e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 125e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa textView = (TextView) inflate.inflate(R.layout.bubble_text, null); 126e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa textView.setBackgroundDrawable(bubbleBackground); 127e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa textView.setText(text); 128e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa if (leftAlign) { 129e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT); 130e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 131e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa window.setContentView(textView); 132e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa window.setFocusable(false); 133e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa window.setTouchable(true); 134e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa window.setOutsideTouchable(false); 135e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 136e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 137e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa private int chooseSize(PopupWindow pop, View parentView, CharSequence text, TextView tv) { 138e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa int wid = tv.getPaddingLeft() + tv.getPaddingRight(); 139e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa int ht = tv.getPaddingTop() + tv.getPaddingBottom(); 140e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 141e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa /* 142e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa * Figure out how big the text would be if we laid it out to the 143e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa * full width of this view minus the border. 144e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa */ 145e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa int cap = width - wid; 146e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 147e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa Layout l = new StaticLayout(text, tv.getPaint(), cap, 148e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa Layout.Alignment.ALIGN_NORMAL, 1, 0, true); 149e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa float max = 0; 150e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa for (int i = 0; i < l.getLineCount(); i++) { 151e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa max = Math.max(max, l.getLineWidth(i)); 152e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 153e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 154e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa /* 155e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa * Now set the popup size to be big enough for the text plus the border. 156e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa */ 157e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa pop.setWidth(width); 158e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa pop.setHeight(ht + l.getHeight()); 159e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa return l.getHeight(); 160e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 161e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 162e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa void show(int offx, int offy) { 163e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa int textHeight = chooseSize(window, inputView, text, textView); 164e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa offy -= textView.getPaddingTop() + textHeight; 165e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa if (inputView.getVisibility() == View.VISIBLE 166e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa && inputView.getWindowVisibility() == View.VISIBLE) { 167e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa try { 168e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa if ((gravity & Gravity.BOTTOM) == Gravity.BOTTOM) offy -= window.getHeight(); 169e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa if ((gravity & Gravity.RIGHT) == Gravity.RIGHT) offx -= window.getWidth(); 170e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa textView.setOnTouchListener(new View.OnTouchListener() { 171e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa public boolean onTouch(View view, MotionEvent me) { 172e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa boolean ret = !mEnableKeyTouch; 173e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa switch (me.getAction()) { 174e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa case MotionEvent.ACTION_UP: 175e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa if (mBubbleIndex >= mBubbles.size()) { 176e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mInputView.setOnTouchListener(null); 177e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } else { 178e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa TutorialEN.this.next(); 179e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 180e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa break; 181e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa default: 182e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa break; 183e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 184e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa return ret; 185e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 186e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa }); 187e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa window.showAtLocation(inputView, Gravity.NO_GRAVITY, x + offx, y + offy); 188e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } catch (Exception e) { 189e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 190e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 191e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 192e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 193e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa void hide() { 194e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa if (window.isShowing()) { 195e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa textView.setOnTouchListener(null); 196e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa window.dismiss(); 197e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 198e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 199e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 200e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa boolean isShowing() { 201e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa return window.isShowing(); 202e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 203e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 204e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 205e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa /** Constructor */ 206e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa public TutorialEN(OpenWnnEN ime, View inputView, DefaultSoftKeyboardEN inputManager) { 207e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mInputView = inputView; 208e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mIme = ime; 209e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 210e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa Context context = inputView.getContext(); 211e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa int inputWidth = inputView.getWidth(); 212e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa Resources r = inputView.getContext().getResources(); 213e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa final int x = inputWidth / 20; 214e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa r.getDimensionPixelOffset(R.dimen.bubble_pointer_offset); 215e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 216e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa SpannableStringBuilder spannable = new SpannableStringBuilder(); 217e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa Bubble button; 218e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 219e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa spannable.clear(); 220e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa spannable.append(r.getText(R.string.tip_en_to_open_keyboard)); 221e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa button = new Bubble(context, inputView, 222e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa R.drawable.dialog_bubble, x, 0, 223e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa spannable, R.string.touch_to_continue, false); 224e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mBubbles.add(button); 225e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 226e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa spannable.clear(); 227e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa spannable.append(r.getText(R.string.tip_en_to_close_keyboard)); 228e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 229e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa setSpan(spannable, "\u2190", R.drawable.tutorial_back); 230e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 231e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa button = new Bubble(context, inputView, 232e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa R.drawable.dialog_bubble, x, 0, 233e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa spannable, R.string.touch_to_continue, false); 234e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mBubbles.add(button); 235e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 236e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa button = new Bubble(context, inputView, 237e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa R.drawable.dialog_bubble, x, 0, 238e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa R.string.tip_en_end_of_tutorial, R.string.touch_to_finish); 239e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mBubbles.add(button); 240e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 241e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 242e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa private void setSpan(SpannableStringBuilder spannable, String marker, int imageResourceId) { 243e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa String text = spannable.toString(); 244e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa int target = text.indexOf(marker); 245e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa while (0 <= target) { 246e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa ImageSpan span = new ImageSpan(mIme, imageResourceId, 247e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa DynamicDrawableSpan.ALIGN_BOTTOM); 248e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa spannable.setSpan(span, target, target + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 249e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa target = text.indexOf(marker, target + 1); 250e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 251e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 252e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 253e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa public void start() { 254e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mInputView.getLocationInWindow(mLocation); 255e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mBubbleIndex = -1; 256e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mInputView.setOnTouchListener(this); 257e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa next(); 258e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 259e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 260e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa boolean next() { 261e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa if (mBubbleIndex >= 0) { 262e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa if (!mBubbles.get(mBubbleIndex).isShowing()) { 263e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa return true; 264e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 265e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa for (int i = 0; i <= mBubbleIndex; i++) { 266e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mBubbles.get(i).hide(); 267e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 268e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 269e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mBubbleIndex++; 270e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa if (mBubbleIndex >= mBubbles.size()) { 271e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mEnableKeyTouch = true; 272e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mIme.sendDownUpKeyEvents(-1); 273e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mIme.tutorialDone(); 274e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa return false; 275e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 276e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 277e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mHandler.sendMessageDelayed( 278e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mHandler.obtainMessage(MSG_SHOW_BUBBLE, mBubbles.get(mBubbleIndex)), 500); 279e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa return true; 280e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 281e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 282e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa void hide() { 283e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa for (int i = 0; i < mBubbles.size(); i++) { 284e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mBubbles.get(i).hide(); 285e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 286e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mInputView.setOnTouchListener(null); 287e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 288e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 289e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa public boolean close() { 290e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mHandler.removeMessages(MSG_SHOW_BUBBLE); 291e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa hide(); 292e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa return true; 293e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 294e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 295e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa public boolean onTouch(View v, MotionEvent event) { 296e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa boolean ret = !mEnableKeyTouch; 297e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa if (event.getAction() == MotionEvent.ACTION_UP) { 298e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa if (mBubbleIndex >= mBubbles.size()) { 299e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mInputView.setOnTouchListener(null); 300e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 301e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 302e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa return ret; 303e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 304e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa} 305