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.JAJP; 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 TutorialJAJP implements OnTouchListener { 59e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 60e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa private List<Bubble> mBubbles = new ArrayList<Bubble>(); 61e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa private static final int LONG_PRESS_INDEX = 8; 62e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa private View mInputView; 63e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa private OpenWnnJAJP mIme; 64e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa private int[] mLocation = new int[2]; 65e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa private static final int MSG_SHOW_BUBBLE = 0; 66e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 67e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa private int mBubbleIndex; 68e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa private DefaultSoftKeyboardJAJP mInputManager; 69e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa private boolean mEnableKeyTouch = false; 70e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 71e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa Handler mHandler = new Handler() { 72e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa @Override 73e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa public void handleMessage(Message msg) { 74e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa switch (msg.what) { 75e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa case MSG_SHOW_BUBBLE: 76e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa Bubble bubba = (Bubble) msg.obj; 77e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa bubba.show(mLocation[0], mLocation[1]); 78e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa break; 79e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 80e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 81e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa }; 82e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 83e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa class Bubble { 84e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa Drawable bubbleBackground; 85e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa int x; 86e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa int y; 87e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa int width; 88e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa int gravity; 89e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa CharSequence text; 90e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa boolean dismissOnTouch; 91e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa boolean dismissOnClose; 92e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa PopupWindow window; 93e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa TextView textView; 94e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa View inputView; 95e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 96e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa Bubble(Context context, View inputView, 97e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa int backgroundResource, int bx, int by, int description, int guide) { 98e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 99e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa CharSequence text = context.getResources().getText(description); 100e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa init(context, inputView, backgroundResource, bx, by, text, guide, false); 101e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 102e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 103e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa Bubble(Context context, View inputView, int backgroundResource, int bx, int by, 104e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa CharSequence description, int guide, boolean leftAlign) { 105e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa init(context, inputView, backgroundResource, bx, by, description, guide, leftAlign); 106e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 107e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 108e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa void init(Context context, View inputView, int backgroundResource, 109e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa int bx, int by, CharSequence description, int guide, boolean leftAlign) { 110e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa bubbleBackground = context.getResources().getDrawable(backgroundResource); 111e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa x = bx; 112e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa y = by; 113e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa width = (int) (inputView.getWidth() * 0.9); 114e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa this.gravity = Gravity.TOP | Gravity.LEFT; 115e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa text = new SpannableStringBuilder() 116e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa .append(description) 117e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa .append("\n") 118e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa .append(context.getResources().getText(guide)); 119e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa this.dismissOnTouch = true; 120e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa this.dismissOnClose = false; 121e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa this.inputView = inputView; 122e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa window = new PopupWindow(context); 123e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa window.setBackgroundDrawable(null); 124e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa LayoutInflater inflate = 125e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa (LayoutInflater) context 126e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 127e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa textView = (TextView) inflate.inflate(R.layout.bubble_text, null); 128e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa textView.setBackgroundDrawable(bubbleBackground); 129e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa textView.setText(text); 130e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa if (leftAlign) { 131e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT); 132e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 133e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa window.setContentView(textView); 134e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa window.setFocusable(false); 135e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa window.setTouchable(true); 136e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa window.setOutsideTouchable(false); 137e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 138e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 139e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa private int chooseSize(PopupWindow pop, View parentView, CharSequence text, TextView tv) { 140e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa int wid = tv.getPaddingLeft() + tv.getPaddingRight(); 141e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa int ht = tv.getPaddingTop() + tv.getPaddingBottom(); 142e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 143e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa /* 144e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa * Figure out how big the text would be if we laid it out to the 145e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa * full width of this view minus the border. 146e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa */ 147e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa int cap = width - wid; 148e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 149e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa Layout l = new StaticLayout(text, tv.getPaint(), cap, 150e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa Layout.Alignment.ALIGN_NORMAL, 1, 0, true); 151e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa float max = 0; 152e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa for (int i = 0; i < l.getLineCount(); i++) { 153e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa max = Math.max(max, l.getLineWidth(i)); 154e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 155e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 156e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa /* 157e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa * Now set the popup size to be big enough for the text plus the border. 158e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa */ 159e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa pop.setWidth(width); 160e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa pop.setHeight(ht + l.getHeight()); 161e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa return l.getHeight(); 162e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 163e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 164e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa void show(int offx, int offy) { 165e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa int textHeight = chooseSize(window, inputView, text, textView); 166e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa offy -= textView.getPaddingTop() + textHeight; 167e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa if (inputView.getVisibility() == View.VISIBLE 168e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa && inputView.getWindowVisibility() == View.VISIBLE) { 169e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa try { 170e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa if ((gravity & Gravity.BOTTOM) == Gravity.BOTTOM) offy -= window.getHeight(); 171e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa if ((gravity & Gravity.RIGHT) == Gravity.RIGHT) offx -= window.getWidth(); 172e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa textView.setOnTouchListener(new View.OnTouchListener() { 173e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa public boolean onTouch(View view, MotionEvent me) { 174e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 175e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa boolean ret = !mEnableKeyTouch; 176e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa switch (me.getAction()) { 177e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa case MotionEvent.ACTION_UP: 178e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa if (mBubbleIndex >= mBubbles.size()) { 179e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mInputView.setOnTouchListener(null); 180e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } else { 181e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa TutorialJAJP.this.next(); 182e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 183e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa break; 184e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa default: 185e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa break; 186e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 187e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa return ret; 188e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 189e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa }); 190e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa window.showAtLocation(inputView, Gravity.NO_GRAVITY, x + offx, y + offy); 191e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } catch (Exception e) { 192e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 193e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 194e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 195e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 196e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa void hide() { 197e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa if (window.isShowing()) { 198e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa textView.setOnTouchListener(null); 199e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa window.dismiss(); 200e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 201e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 202e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 203e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa boolean isShowing() { 204e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa return window.isShowing(); 205e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 206e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 207e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 208e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa /** Constructor */ 209e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa public TutorialJAJP(OpenWnnJAJP ime, View inputView, DefaultSoftKeyboardJAJP inputManager) { 210e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mInputManager = inputManager; 211e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mInputView = inputView; 212e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mIme = ime; 213e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 214e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa Context context = inputView.getContext(); 215e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa int inputWidth = inputView.getWidth(); 216e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa Resources r = inputView.getContext().getResources(); 217e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa final int x = inputWidth / 20; 218e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa r.getDimensionPixelOffset(R.dimen.bubble_pointer_offset); 219e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 220e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa SpannableStringBuilder spannable = new SpannableStringBuilder(); 221e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa Bubble button; 222e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 223e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa spannable.clear(); 224e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa spannable.append(r.getText(R.string.tip_to_step1)); 225e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 226e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa setSpan(spannable, "\u25cb", R.drawable.tutorial_12key_key); 227e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa button = new Bubble(context, inputView, 228e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa R.drawable.dialog_bubble, x, 0, 229e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa spannable, R.string.touch_to_continue, false); 230e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mBubbles.add(button); 231e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 232e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa spannable.clear(); 233e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa spannable.append(r.getText(R.string.tip_to_step2_a)); 234e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 235e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa setSpan(spannable, "\u25cb", R.drawable.tutorial_12key_toggle); 236e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa button = new Bubble(context, inputView, 237e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa R.drawable.dialog_bubble, x, 0, 238e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa spannable, R.string.touch_to_continue, true); 239e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mBubbles.add(button); 240e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 241e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa spannable.append(r.getText(R.string.tip_to_step2_b)); 242e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 243e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa setSpan(spannable, "\u2192", R.drawable.tutorial_12key_right); 244e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 245e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa button = new Bubble(context, inputView, 246e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa R.drawable.dialog_bubble, x, 0, 247e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa spannable, R.string.touch_to_continue, true); 248e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mBubbles.add(button); 249e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 250e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa spannable.append(r.getText(R.string.tip_to_step2_c)); 251e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 252e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa setSpan(spannable, "\u25cb", R.drawable.tutorial_12key_toggle); 253e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 254e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa button = new Bubble(context, inputView, 255e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa R.drawable.dialog_bubble, x, 0, 256e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa spannable, R.string.touch_to_continue, true); 257e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mBubbles.add(button); 258e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 259e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa spannable.append(r.getText(R.string.tip_to_step2_d)); 260e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 261e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa setSpan(spannable, "\u25a0", R.drawable.tutorial_12key_space_jp); 262e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 263e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa setSpan(spannable, "\u2193", R.drawable.tutorial_12key_enter); 264e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 265e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa button = new Bubble(context, inputView, 266e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa R.drawable.dialog_bubble, x, 0, 267e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa spannable, R.string.touch_to_continue, true); 268e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mBubbles.add(button); 269e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 270e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa spannable.clear(); 271e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa spannable.append(r.getText(R.string.tip_to_step3_a)); 272e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 273e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa setSpan(spannable, "\u25a0", R.drawable.tutorial_12key_mode); 274e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa button = new Bubble(context, inputView, 275e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa R.drawable.dialog_bubble_moji, x, 0, 276e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa spannable, R.string.touch_to_continue, false); 277e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mBubbles.add(button); 278e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 279e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa button = new Bubble(context, inputView, 280e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa R.drawable.dialog_bubble_moji, x, 0, 281e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa R.string.tip_to_step3_b, R.string.touch_to_continue); 282e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mBubbles.add(button); 283e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 284e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa button = new Bubble(context, inputView, 285e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa R.drawable.dialog_bubble_moji, x, 0, 286e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa R.string.tip_to_step3_c, R.string.touch_to_continue); 287e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mBubbles.add(button); 288e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 289e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa spannable.clear(); 290e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa spannable.append(r.getText(R.string.tip_to_step4)); 291e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 292e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa setSpan(spannable, "\u25a0", R.drawable.tutorial_12key_mode); 293e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa button = new Bubble(context, inputView, 294e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa R.drawable.dialog_bubble_moji, x, 0, 295e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa spannable, R.string.touch_to_try, false); 296e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mBubbles.add(button); 297e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 298e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa spannable.clear(); 299e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa spannable.append(r.getText(R.string.tip_to_step5)); 300e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 301e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa setSpan(spannable, "\u2190", R.drawable.tutorial_back); 302e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 303e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa button = new Bubble(context, inputView, 304e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa R.drawable.dialog_bubble, x, 0, 305e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa spannable, R.string.touch_to_continue, false); 306e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mBubbles.add(button); 307e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 308e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa button = new Bubble(context, inputView, 309e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa R.drawable.dialog_bubble, x, 0, 310e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa R.string.tip_to_step6, R.string.touch_to_finish); 311e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mBubbles.add(button); 312e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 313e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 314e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa private void setSpan(SpannableStringBuilder spannable, String marker, int imageResourceId) { 315e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa String text = spannable.toString(); 316e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa int target = text.indexOf(marker); 317e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa while (0 <= target) { 318e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa ImageSpan span = new ImageSpan(mIme, imageResourceId, 319e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa DynamicDrawableSpan.ALIGN_BOTTOM); 320e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa spannable.setSpan(span, target, target + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 321e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa target = text.indexOf(marker, target + 1); 322e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 323e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 324e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 325e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa public void start() { 326e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mInputView.getLocationInWindow(mLocation); 327e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mBubbleIndex = -1; 328e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mInputView.setOnTouchListener(this); 329e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa next(); 330e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 331e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 332e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa boolean next() { 333e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa if (mBubbleIndex >= 0) { 334e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa if (!mBubbles.get(mBubbleIndex).isShowing()) { 335e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa return true; 336e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 337e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa for (int i = 0; i <= mBubbleIndex; i++) { 338e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mBubbles.get(i).hide(); 339e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 340e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 341e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mBubbleIndex++; 342e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa if (mBubbleIndex >= mBubbles.size()) { 343e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mEnableKeyTouch = true; 344e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mIme.sendDownUpKeyEvents(-1); 345e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mIme.tutorialDone(); 346e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa return false; 347e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 348e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 349e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa if ((6 <= mBubbleIndex) && (mBubbleIndex <= 8)) { 350e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mInputManager.nextKeyMode(); 351e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 352e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 353e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa if (mBubbleIndex == LONG_PRESS_INDEX) { 354e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mEnableKeyTouch = true; 355e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } else if (LONG_PRESS_INDEX < mBubbleIndex) { 356e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mEnableKeyTouch = false; 357e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 358e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 359e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mHandler.sendMessageDelayed( 360e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mHandler.obtainMessage(MSG_SHOW_BUBBLE, mBubbles.get(mBubbleIndex)), 500); 361e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa return true; 362e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 363e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 364e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa void hide() { 365e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa for (int i = 0; i < mBubbles.size(); i++) { 366e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mBubbles.get(i).hide(); 367e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 368e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mInputView.setOnTouchListener(null); 369e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 370e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 371e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa public boolean close() { 372e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mHandler.removeMessages(MSG_SHOW_BUBBLE); 373e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa hide(); 374e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa return true; 375e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 376e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa 377e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa public boolean onTouch(View v, MotionEvent event) { 378e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa boolean ret = !mEnableKeyTouch; 379e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa if (event.getAction() == MotionEvent.ACTION_UP) { 380e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa if (mBubbleIndex >= mBubbles.size()) { 381e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa mInputView.setOnTouchListener(null); 382e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } else { 383e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa if (mBubbleIndex != LONG_PRESS_INDEX) { 384e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa next(); 385e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 386e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 387e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 388e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa return ret; 389e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa } 390e83971e4dafd53e9fb00386355afdbae7e00c0cfDaisuke Miyakawa} 391