com.anysoftkeyboard.keyboards.views.AnyKeyboardViewWithMiniKeyboard.java Source code

Java tutorial

Introduction

Here is the source code for com.anysoftkeyboard.keyboards.views.AnyKeyboardViewWithMiniKeyboard.java

Source

/*
 * Copyright (c) 2016 Menny Even-Danan
 *
 * 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.
 */

package com.anysoftkeyboard.keyboards.views;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.os.SystemClock;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.view.MotionEventCompat;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.PopupWindow;

import com.anysoftkeyboard.AskPrefs;
import com.anysoftkeyboard.addons.AddOn;
import com.anysoftkeyboard.base.utils.CompatUtils;
import com.anysoftkeyboard.keyboards.AnyPopupKeyboard;
import com.anysoftkeyboard.keyboards.Keyboard;
import com.menny.android.anysoftkeyboard.AnyApplication;
import com.menny.android.anysoftkeyboard.R;

/**
 * Supports popup keyboard when {@link com.anysoftkeyboard.keyboards.AnyKeyboard.AnyKey} says it has
 * that, and user long-press that key.
 */

public class AnyKeyboardViewWithMiniKeyboard extends SizeSensitiveAnyKeyboardView {

    public interface OnPopupShownListener {
        void onPopupKeyboardShowingChanged(boolean showing);
    }

    private AnyKeyboardViewBase mMiniKeyboard = null;
    private int mMiniKeyboardOriginX;
    private int mMiniKeyboardOriginY;
    private long mMiniKeyboardPopupTime;
    protected AskPrefs.AnimationsLevel mAnimationLevel = AnyApplication.getConfig().getAnimationsLevel();

    final PopupWindow mMiniKeyboardPopup;

    protected final MiniKeyboardActionListener mChildKeyboardActionListener = new MiniKeyboardActionListener(this);

    @Nullable
    private OnPopupShownListener mPopupShownListener;

    public AnyKeyboardViewWithMiniKeyboard(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public AnyKeyboardViewWithMiniKeyboard(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        mMiniKeyboardPopup = new PopupWindow(context.getApplicationContext());
        CompatUtils.setPopupUnattachedToDecor(mMiniKeyboardPopup);
        mMiniKeyboardPopup.setBackgroundDrawable(null);
        mMiniKeyboardPopup.setAnimationStyle(
                (mAnimationLevel == AskPrefs.AnimationsLevel.None) ? 0 : R.style.MiniKeyboardAnimation);
    }

    public void setOnPopupShownListener(@Nullable OnPopupShownListener listener) {
        mPopupShownListener = listener;
    }

    protected final AnyKeyboardViewBase getMiniKeyboard() {
        return mMiniKeyboard;
    }

    @Override
    public boolean onTouchEvent(@NonNull MotionEvent me) {
        if (getMiniKeyboard() != null && mMiniKeyboardPopup.isShowing()) {
            final int miniKeyboardX = (int) me.getX();
            final int miniKeyboardY = (int) me.getY();
            final int action = MotionEventCompat.getActionMasked(me);

            MotionEvent translated = generateMiniKeyboardMotionEvent(action, miniKeyboardX, miniKeyboardY,
                    me.getEventTime());
            getMiniKeyboard().onTouchEvent(translated);
            translated.recycle();
            return true;
        }

        return super.onTouchEvent(me);
    }

    @Override
    public boolean isShifted() {
        if (mMiniKeyboardPopup.isShowing())
            return mMiniKeyboard.isShifted();

        return super.isShifted();
    }

    private void setupMiniKeyboardContainer(@NonNull AddOn keyboardAddOn, @NonNull Keyboard.Key popupKey,
            boolean isSticky) {
        final AnyPopupKeyboard keyboard;
        if (popupKey.popupCharacters != null) {
            //in this case, we must use ASK's context to inflate views and XMLs
            keyboard = new AnyPopupKeyboard(mDefaultAddOn, getContext().getApplicationContext(),
                    popupKey.popupCharacters, mMiniKeyboard.getThemedKeyboardDimens(), null);
        } else {
            keyboard = new AnyPopupKeyboard(keyboardAddOn, getContext().getApplicationContext(),
                    popupKey.externalResourcePopupLayout ? keyboardAddOn.getPackageContext()
                            : getContext().getApplicationContext(),
                    popupKey.popupResId, mMiniKeyboard.getThemedKeyboardDimens(), null);
        }

        if (isSticky) {
            //using the vertical correction this keyboard has, since the input should behave
            //just as the mParent keyboard
            mMiniKeyboard.setKeyboard(keyboard, mOriginalVerticalCorrection);
        } else {
            //not passing vertical correction, so the popup keyboard will use its own correction
            mMiniKeyboard.setKeyboard(keyboard, mNextAlphabetKeyboardName, mNextSymbolsKeyboardName);
        }

        mMiniKeyboard.measure(MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST),
                MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.AT_MOST));
    }

    @Override
    protected void onBufferDraw(Canvas canvas, Paint paint) {
        super.onBufferDraw(canvas, paint);

        // Overlay a dark rectangle to dim the keyboard
        if (mMiniKeyboardPopup.isShowing()) {
            paint.setColor((int) (mBackgroundDimAmount * 0xFF) << 24);
            canvas.drawRect(0, 0, getWidth(), getHeight(), paint);
        }
    }

    @SuppressLint("InflateParams")
    public void ensureMiniKeyboardInitialized() {
        if (mMiniKeyboard != null)
            return;

        LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        mMiniKeyboard = (AnyKeyboardViewBase) inflater.inflate(R.layout.popup_keyboard_layout, null);

        mMiniKeyboard.setOnKeyboardActionListener(mChildKeyboardActionListener);
    }

    protected void setPopupKeyboardWithView(int x, int y, int originX, int originY, View contentView) {
        mMiniKeyboardOriginX = originX;
        mMiniKeyboardOriginY = originY;

        mMiniKeyboardPopup.setContentView(contentView);
        CompatUtils.setPopupUnattachedToDecor(mMiniKeyboardPopup);
        mMiniKeyboardPopup.setWidth(contentView.getMeasuredWidth());
        mMiniKeyboardPopup.setHeight(contentView.getMeasuredHeight());
        mMiniKeyboardPopup.showAtLocation(this, Gravity.NO_GRAVITY, x, y);

        invalidateAllKeys();
    }

    private MotionEvent generateMiniKeyboardMotionEvent(int action, int x, int y, long eventTime) {
        return MotionEvent.obtain(mMiniKeyboardPopupTime, eventTime, action, x - mMiniKeyboardOriginX,
                y - mMiniKeyboardOriginY, 0);
    }

    @Override
    protected boolean onLongPress(AddOn keyboardAddOn, Keyboard.Key key, boolean isSticky,
            @NonNull PointerTracker tracker) {
        if (super.onLongPress(keyboardAddOn, key, isSticky, tracker))
            return true;
        if (key.popupResId == 0)
            return false;

        showMiniKeyboardForPopupKey(keyboardAddOn, key, isSticky);
        return true;
    }

    protected void showMiniKeyboardForPopupKey(@NonNull AddOn keyboardAddOn, @NonNull Keyboard.Key popupKey,
            boolean isSticky) {
        int[] windowOffset = getLocationInWindow();

        ensureMiniKeyboardInitialized();

        setupMiniKeyboardContainer(keyboardAddOn, popupKey, isSticky);

        Point miniKeyboardPosition = PopupKeyboardPositionCalculator.calculatePositionForPopupKeyboard(popupKey,
                this, mMiniKeyboard, mPreviewPopupTheme, windowOffset);

        final int x = miniKeyboardPosition.x;
        final int y = miniKeyboardPosition.y;

        final int originX = x - windowOffset[0];
        final int originY = y + mMiniKeyboard.getPaddingTop() - windowOffset[1];

        // NOTE:I'm checking the main keyboard shift state directly!
        // Not anything else.
        mMiniKeyboard.setShifted(getKeyboard() != null && getKeyboard().isShifted());
        // Mini keyboard needs no pop-up key preview displayed.
        mMiniKeyboard.setPreviewEnabled(false);

        setPopupKeyboardWithView(x, y, originX, originY, mMiniKeyboard);

        setPopupStickinessValues(isSticky, !isSticky, popupKey.x + popupKey.width / 2,
                popupKey.y + popupKey.height / 2);

        dismissAllKeyPreviews();

        if (mPopupShownListener != null)
            mPopupShownListener.onPopupKeyboardShowingChanged(true);
    }

    protected void setPopupStickinessValues(boolean isSticky, boolean requiresSlideInMotionEvent, int touchX,
            int touchY) {
        mChildKeyboardActionListener.setInOneShot(!isSticky);
        if (requiresSlideInMotionEvent) {
            // Inject down event on the key to mini keyboard.
            long eventTime = SystemClock.uptimeMillis();
            mMiniKeyboardPopupTime = eventTime;
            MotionEvent downEvent = generateMiniKeyboardMotionEvent(MotionEvent.ACTION_DOWN, touchX, touchY,
                    eventTime);
            mMiniKeyboard.onTouchEvent(downEvent);
            downEvent.recycle();
        }

    }

    public boolean dismissPopupKeyboard() {
        if (mMiniKeyboardPopup.isShowing()) {
            if (mMiniKeyboard != null)
                mMiniKeyboard.closing();
            mMiniKeyboardPopup.dismiss();
            mMiniKeyboardOriginX = 0;
            mMiniKeyboardOriginY = 0;
            mPointerQueue.cancelAllPointers();
            invalidateAllKeys();
            if (mPopupShownListener != null)
                mPopupShownListener.onPopupKeyboardShowingChanged(false);
            return true;
        } else {
            return false;
        }
    }

    @Override
    public void disableTouchesTillFingersAreUp() {
        super.disableTouchesTillFingersAreUp();
        dismissPopupKeyboard();
    }

    @Override
    public boolean closing() {
        super.closing();

        return !dismissPopupKeyboard();
    }

    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
        super.onSharedPreferenceChanged(sharedPreferences, key);

        mAnimationLevel = AnyApplication.getConfig().getAnimationsLevel();
        mMiniKeyboardPopup.setAnimationStyle(
                (mAnimationLevel == AskPrefs.AnimationsLevel.None) ? 0 : R.style.MiniKeyboardAnimation);
    }

    @Override
    public void onViewNotRequired() {
        super.onViewNotRequired();
        CompatUtils.unbindDrawable(mPreviewPopupTheme.getPreviewKeyBackground());
        if (mMiniKeyboard != null)
            mMiniKeyboard.onViewNotRequired();
        mMiniKeyboard = null;
    }

    public boolean handleBack() {
        if (mMiniKeyboardPopup.isShowing()) {
            dismissPopupKeyboard();
            return true;
        }
        return false;
    }
}