/** * Copyright 2015 YA LLC * * * 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 chat.rocket.android.widget.emoji import android.content.Context import android.graphics.Point import android.graphics.Rect import android.os.Build import android.view.* import android.widget.PopupWindow import chat.rocket.android.BuildConfig import chat.rocket.android.R /** * Base class to create popup window that appears over software keyboard. */ abstract class OverKeyboardPopupWindow(val context: Context, private val rootView: View) : PopupWindow(context), ViewTreeObserver.OnGlobalLayoutListener { /** * @return keyboard height in pixels */ var keyboardHeight = 0 private set private var pendingOpen = false /** * @return Returns true if the soft keyboard is open, false otherwise. */ var isKeyboardOpen = false private set private var keyboardHideListener: OnKeyboardHideListener? = null interface OnKeyboardHideListener { fun onKeyboardHide() } init { setBackgroundDrawable(null) if (BuildConfig.VERSION_CODE >= Build.VERSION_CODES.LOLLIPOP) { elevation = 0f } val view = onCreateView(LayoutInflater.from(context)) onViewCreated(view) contentView = view softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE // Default size setSize(this.context.resources.getDimensionPixelSize(R.dimen.supposed_keyboard_height), WindowManager.LayoutParams.MATCH_PARENT) setSizeForSoftKeyboard() } fun setKeyboardHideListener(keyboardHideListener: OnKeyboardHideListener) { this.keyboardHideListener = keyboardHideListener } /** * Manually set the popup window size * * @param width Width of the popup * @param height Height of the popup */ fun setSize(width: Int, height: Int) { setWidth(width) setHeight(height) } /** * Call this function to resize the emoji popup according to your soft keyboard size */ fun setSizeForSoftKeyboard() { val viewTreeObserver = rootView.viewTreeObserver viewTreeObserver.addOnGlobalLayoutListener(this) } override fun onGlobalLayout() { val r = Rect() rootView.getWindowVisibleDisplayFrame(r) val screenHeight = calculateScreenHeight() var heightDifference = screenHeight - (r.bottom - r.top) val resources = context.resources val resourceId = resources.getIdentifier("status_bar_height", "dimen", "android") if (resourceId > 0) { heightDifference -= resources.getDimensionPixelSize(resourceId) } if (heightDifference > 100) { keyboardHeight = heightDifference setSize(WindowManager.LayoutParams.MATCH_PARENT, keyboardHeight) isKeyboardOpen = true if (pendingOpen) { showAtBottom() pendingOpen = false } } else { if (isKeyboardOpen && keyboardHideListener != null) { keyboardHideListener!!.onKeyboardHide() } isKeyboardOpen = false } } private fun calculateScreenHeight(): Int { val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager val display = wm.getDefaultDisplay() val size = Point() display.getSize(size) return size.y } /** * Use this function to show the popup. * NOTE: Since, the soft keyboard sizes are variable on different android devices, the * library needs you to open the soft keyboard at least once before calling this function. * If that is not possible see showAtBottomPending() function. */ fun showAtBottom() { showAtLocation(rootView, Gravity.BOTTOM, 0, 0) } /** * Use this function when the soft keyboard has not been opened yet. This * will show the popup after the keyboard is up next time. * Generally, you will be calling InputMethodManager.showSoftInput function after * calling this function. */ fun showAtBottomPending() { if (isKeyboardOpen) { showAtBottom() } else { pendingOpen = true } } abstract fun onCreateView(inflater: LayoutInflater): View abstract fun onViewCreated(view: View) }