All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.solovyev.android.keyboard.DragAndroidKeyboardView Maven / Gradle / Ivy

/*
 * Copyright 2013 serso aka se.solovyev
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * Contact details
 *
 * Email: [email protected]
 * Site:  http://se.solovyev.org
 */

package org.solovyev.android.keyboard;

import android.app.Activity;
import android.content.Context;
import android.inputmethodservice.KeyboardView;
import android.os.Vibrator;
import android.preference.PreferenceManager;
import android.util.AttributeSet;
import android.view.*;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.solovyev.android.Views;
import org.solovyev.android.view.AndroidViewUtils;
import org.solovyev.android.view.VibratorContainer;
import org.solovyev.android.view.drag.DirectionDragButton;
import org.solovyev.android.view.drag.DragButton;
import org.solovyev.android.view.drag.DragDirection;
import org.solovyev.android.view.drag.SimpleOnDragListener;
import org.solovyev.common.math.Point2d;
import org.solovyev.common.text.Strings;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.Map;

/**
 * User: Solovyev_S
 * Date: 02.11.12
 * Time: 14:47
 */
public class DragAndroidKeyboardView extends LinearLayout implements AndroidKeyboardView, SimpleOnDragListener.DragProcessor, View.OnTouchListener, View.OnClickListener {

	@Nullable
	private KeyboardView.OnKeyboardActionListener keyboardActionListener;

	@Nonnull
	private AKeyboardButtonPreview preview;

	@Nonnull
	private final RepeatHelper repeatHelper = new RepeatHelper();

	@Nonnull
	private final Map defs = new HashMap();

	@Nonnull
	private final VibratorContainer vibrator;

	@Nullable
	private DragAKeyboard keyboard;

	public DragAndroidKeyboardView(Context context) {
		super(context);
		preview = new AKeyboardButtonPreview(this);
		vibrator = new VibratorContainer((Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE), PreferenceManager.getDefaultSharedPreferences(context), 1f);
	}

	public DragAndroidKeyboardView(Context context, AttributeSet attrs) {
		super(context, attrs);
		preview = new AKeyboardButtonPreview(this);
		vibrator = new VibratorContainer((Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE), PreferenceManager.getDefaultSharedPreferences(context), 1f);
	}

	public DragAndroidKeyboardView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		preview = new AKeyboardButtonPreview(this);
		vibrator = new VibratorContainer((Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE), PreferenceManager.getDefaultSharedPreferences(context), 1f);
	}

	@Override
	public void setOnKeyboardActionListener(@Nonnull KeyboardView.OnKeyboardActionListener keyboardActionListener) {
		this.keyboardActionListener = keyboardActionListener;
	}

	@Override
	public void setKeyboard(@Nonnull DragAKeyboard keyboard) {
		setKeyboard(keyboard, null);
	}

	@Override
	public void close() {
		this.preview.hide();
	}

	@Override
	public void dismiss() {
		this.preview.hide();
	}

	@Override
	public void reload() {
		if (keyboard != null) {
			reloadView(keyboard, null);
		}
	}

	private void setKeyboard(@Nullable DragAKeyboard keyboard,
							 @Nullable LayoutInflater layoutInflater) {
		if (keyboard != null) {
			this.keyboard = keyboard;
			reloadView(keyboard, layoutInflater);
		}
	}

	private void reloadView(@Nonnull DragAKeyboard keyboard, @Nullable LayoutInflater layoutInflater) {
		dismiss();

		final DragAKeyboard.KeyboardDef keyboardDef = keyboard.getKeyboardDef();

		final Context context = this.getContext();
		int buttonMargin = Views.toPixels(context.getResources().getDisplayMetrics(), 0.5f);

		if (layoutInflater == null) {
			layoutInflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
		}

		preview.createPreviewView(layoutInflater);

		final SimpleOnDragListener.Preferences defaultPreferences = SimpleOnDragListener.getDefaultPreferences(context);
		this.removeAllViews();

		this.defs.clear();

		for (DragAKeyboard.RowDef rowDef : keyboardDef.getRowDefs()) {
			final LinearLayout rowLayout = new LinearLayout(context);
			rowLayout.setOrientation(LinearLayout.HORIZONTAL);
			for (DragAKeyboardButtonDef buttonDef : rowDef.getButtonDefs()) {

				Float weight = buttonDef.getLayoutWeight();
				if (weight == null) {
					weight = 1f;
				}
				final LayoutParams params = new LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT, weight);

				Integer layoutMarginLeft = buttonDef.getLayoutMarginLeft();
				if (layoutMarginLeft != null) {
					params.leftMargin = layoutMarginLeft;
				} else {
					params.leftMargin = buttonMargin;
				}

				Integer layoutMarginRight = buttonDef.getLayoutMarginRight();
				if (layoutMarginRight != null) {
					params.rightMargin = layoutMarginRight;
				} else {
					params.rightMargin = buttonMargin;
				}

				params.topMargin = buttonMargin;
				params.bottomMargin = buttonMargin;

				final Integer drawableResId = buttonDef.getDrawableResId();
				if (drawableResId == null) {
					final DirectionDragButton directionDragButton = (DirectionDragButton) layoutInflater.inflate(R.layout.drag_keyboard_drag_button, null);
					directionDragButton.applyDef(buttonDef);
					directionDragButton.setOnDragListener(new SimpleOnDragListener(this, defaultPreferences));
					// we cannot use on touch listener here (in order to get repeat) as it will conflict with default DragButton logic
					directionDragButton.setOnClickListener(this);
					defs.put(directionDragButton, buttonDef);
					rowLayout.addView(directionDragButton, params);
				} else {
					final ImageButton imageButton = (ImageButton) layoutInflater.inflate(R.layout.drag_keyboard_image_button, null);
					AndroidViewUtils.applyButtonDef(imageButton, buttonDef);
					imageButton.setOnTouchListener(this);
					defs.put(imageButton, buttonDef);
					rowLayout.addView(imageButton, params);
				}
			}
			final LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0, 1);
			params.gravity = Gravity.CENTER_HORIZONTAL;
			this.addView(rowLayout, params);
		}
	}

	@Override
	public boolean processDragEvent(@Nonnull DragDirection dragDirection, @Nonnull DragButton dragButton, @Nonnull Point2d startPoint2d, @Nonnull MotionEvent motionEvent) {
		if (dragButton instanceof DirectionDragButton) {
			final DirectionDragButton directionDragButton = (DirectionDragButton) dragButton;

			vibrator.vibrate();

			final Integer keycode = getKeycode(dragDirection, dragButton);

			return handleTextOrCode(dragButton, directionDragButton.getText(dragDirection), keycode, true, dragDirection);
		}
		return false;
	}

	private Integer getKeycode(@Nullable DragDirection dragDirection,
							   @Nonnull View view) {
		Integer keycode = null;
		final DragAKeyboardButtonDef buttonDef = this.defs.get(view);
		if (buttonDef != null) {
			if (dragDirection != null) {
				keycode = buttonDef.getDirectionKeycode(dragDirection);
			} else {
				keycode = buttonDef.getKeycode();
			}

		}
		return keycode;
	}

	private boolean handleTextOrCode(@Nonnull View view,
									 @Nullable CharSequence text,
									 @Nullable Integer keycode,
									 boolean withPreview,
									 @Nullable DragDirection dragDirection) {
		// we need to check if there is something in the tag

		if (keycode != null) {
			return handleKeycode(view, text, keycode, withPreview, dragDirection);
		} else {
			return handleText(view, text, withPreview, dragDirection);
		}
	}

	private boolean handleKeycode(@Nonnull View view,
								  @Nullable CharSequence text,
								  @Nonnull Integer keycode,
								  boolean withPreview,
								  @Nullable DragDirection dragDirection) {
		if (withPreview) {
			showPreview(view, text, dragDirection);
		}

		if (keyboardActionListener != null) {
			keyboardActionListener.onKey(keycode, null);
		}

		return true;
	}

	private boolean handleText(@Nonnull View view, @Nullable CharSequence text, boolean withPreview, @Nullable DragDirection dragDirection) {
		if (!Strings.isEmpty(text)) {

			if (withPreview) {
				showPreview(view, text, dragDirection);
			}

			if (keyboardActionListener != null) {
				keyboardActionListener.onText(text);
			}

			return true;
		}
		return false;
	}

	private void showPreview(@Nonnull View view,
							 @Nullable CharSequence text,
							 @Nullable DragDirection direction) {

		final DragAKeyboardButtonDef buttonDef = defs.get(view);

		if (buttonDef != null) {

			CharSequence previewText;
			if (direction != null) {
				previewText = buttonDef.getPreviewDirectionText(direction);
			} else {
				previewText = buttonDef.getPreviewText();
			}

			Integer previewDrawableResId = null;

			if (direction == null) {
				previewDrawableResId = buttonDef.getPreviewDrawableResId();
			}

			if (previewDrawableResId == null) {
				previewDrawableResId = buttonDef.getDrawableResId();
			}

			if (previewText == null && previewDrawableResId == null) {
				previewText = text;
			}

			preview.showPreview(view, previewText, previewDrawableResId);
		} else {
			preview.showPreview(view, text, null);
		}
	}

	@Override
	public boolean onTouch(@Nonnull final View v, @Nonnull MotionEvent event) {
		switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				if (isRepeatAllowed(v)) {
					repeatHelper.keyDown(v, new RepeatKeydownRunnable(v));
				} else {
					repeatHelper.keyDown(v, null);
					doKeydown(v);
				}
				return true;

			case MotionEvent.ACTION_UP:
				repeatHelper.keyUp(v);
				return true;
		}

		return false;
	}

	private boolean isRepeatAllowed(View v) {
		boolean allowRepeat = false;

		final DragAKeyboardButtonDef buttonDef = defs.get(v);
		if (buttonDef != null) {
			allowRepeat = buttonDef.allowRepeat();
		}

		return allowRepeat;
	}

	@Override
	public void onClick(View v) {
		vibrator.vibrate();

		final Integer keycode = getKeycode(null, v);

		if (v instanceof TextView) {
			handleTextOrCode(v, ((TextView) v).getText(), keycode, true, null);
		} else {
			handleTextOrCode(v, null, keycode, true, null);
		}
	}

	private class RepeatKeydownRunnable implements Runnable {

		private final View view;

		public RepeatKeydownRunnable(@Nonnull View view) {
			this.view = view;
		}

		@Override
		public void run() {
			doKeydown(view);
		}
	}

	private void doKeydown(@Nonnull View view) {
		final Integer keycode = getKeycode(null, view);

		if (view instanceof TextView) {
			handleTextOrCode(view, ((TextView) view).getText(), keycode, true, null);
		} else {
			handleTextOrCode(view, null, keycode, true, null);
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy