blob: 6d8bb485e74d9f437d783711a130113d02de2e48 [file] [log] [blame]
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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 org.apache.cordova;
import org.apache.cordova.LOG;
import android.content.Context;
//import android.view.View.MeasureSpec;
import android.widget.LinearLayout;
/**
* This class is used to detect when the soft keyboard is shown and hidden in the web view.
*/
public class LinearLayoutSoftKeyboardDetect extends LinearLayout {
private static final String TAG = "SoftKeyboardDetect";
// Kindle Fire devices have a Soft Key Bar with Home, Back and Search buttons that is displayed by default if the
// application is not set to full screen mode. As a result,
// In portrait mode - Contanier's Height = Screen Height - Status Bar Height - Soft Key Bar Height, Container's
// Width = Screen Width
// In landscape mode - Contanier's Height = Screen Height - Status Bar Height, Contanier's Width = Screen Width -
// Soft Key Bar Width
//
// Screen width and height for 3rd generation Kindle Fire devices are listed below
// Kindle Fire HDX 8.9" Screen Height = 2560 Screen Width = 1600
// [In portrait mode] SoftKeyBar Height = 122 (4.76% of Screen Height)
// [In landscape mode] SoftKeyBar Width = 122 (4.76% of Screen Width)
// Kindle Fire HDX 7" Screen Height = 1920 Screen Width = 1200
// [In portrait mode] SoftKeyBar Height = 117 (6.3% of Screen Height)
// [In landscape mode] SoftKeyBar Width = 117 (6.3% of Screen Width)
// Kindle Fire HD 7" Screen Height = 1280 Screen Width = 800
// [In portrait mode] SoftKeyBar Height = 78 (6.09% of Screen Height)
// [In landscape mode] SoftKeyBar Width = 78 (6.09% of Screen Width)
//
// Show/Hide keyboard events
// Should be fired when the height of the container changes by a value equal to the height of the keyboard.
// Our implementation - These events will be fired when the change in the height of the container is more than 7% of
// the screen height. This threshold value was chosen based on the height of the Soft Key Bar in the 3rd generation
// devices. This change has been added so that the show/hide keyboard events are not wrongly triggered when the soft
// key bar shows up.
//
// Orientation change
// [Landscape to Portrait] Screen Height should be equal to Container Width
// [Portrait to Landscape] Screen Height should be equal to Container Width + Soft Key Bar Width
// Our Implementation - Orientation change occurs when the difference between screen height and container width is
// less than 7% of the screen height. This threshold value was chosen based on the height of the Soft Key Bar in the
// 3rd generation devices.
private static final int PERCENTAGE_CHANGE_THRESHOLD = 7;
private int oldHeight = 0; // Need to save the old height as not to send redundant events
private int oldWidth = 0; // Need to save old width for orientation change
private int screenWidth = 0;
private int screenHeight = 0;
private CordovaActivity app = null;
public LinearLayoutSoftKeyboardDetect(Context context, int width, int height) {
super(context);
screenWidth = width;
screenHeight = height;
app = (CordovaActivity) context;
}
@Override
/**
* Start listening to new measurement events. Fire events when the height
* gets smaller fire a show keyboard event and when height gets bigger fire
* a hide keyboard event.
*
* Note: We are using app.postMessage so that this is more compatible with the API
*
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
LOG.v(TAG, "We are in our onMeasure method");
// Get the current height of the visible part of the screen.
// This height will not included the status bar.\
int width, height;
height = MeasureSpec.getSize(heightMeasureSpec);
width = MeasureSpec.getSize(widthMeasureSpec);
LOG.v(TAG, "Old Height = %d", oldHeight);
LOG.v(TAG, "Height = %d", height);
LOG.v(TAG, "Old Width = %d", oldWidth);
LOG.v(TAG, "Width = %d", width);
// If the oldHeight = 0 then this is the first measure event as the app starts up.
// If oldHeight == height then we got a measurement change that doesn't affect us.
if (oldHeight == 0 || oldHeight == height) {
LOG.d(TAG, "Ignore this event");
}
// Account for orientation change and ignore this event/Fire orientation change
else if (hasOrientationChanged(width)) {
int tmp_var = screenHeight;
screenHeight = screenWidth;
screenWidth = tmp_var;
LOG.v(TAG, "Orientation Change");
}
// If the height has gotten bigger then we will assume the soft keyboard has
// gone away.
else if (height > oldHeight) {
if (app != null && hasKeyboardEventOccurred(height) ) {
LOG.v(TAG, "Fired Hide Keyboard Event") ;
app.appView.sendJavascript("cordova.fireDocumentEvent('hidekeyboard');");
}
}
// If the height has gotten smaller then we will assume the soft keyboard has
// been displayed.
else if (height < oldHeight) {
if (app != null && hasKeyboardEventOccurred(height) ) {
LOG.v(TAG, "Fired Show Keyboard Event") ;
app.appView.sendJavascript("cordova.fireDocumentEvent('showkeyboard');");
}
}
// Update the old height for the next event
oldHeight = height;
oldWidth = width;
}
/**
* Function that returns true if orientation has changed
*
* @param width
* The width of the container
* @return
*/
private boolean hasOrientationChanged(int width) {
//Calculate difference between screen height and container as a percentage of screen height
double percentageChange = (double) (Math.abs(screenHeight - width) * 100) / screenHeight;
return percentageChange < PERCENTAGE_CHANGE_THRESHOLD;
}
/**
* Function that returns true if the keyboard show/hide event has occurred.
*
* @param height
* The height of the container
* @return
*/
private boolean hasKeyboardEventOccurred(int height) {
//Calculate percentage change in container height as a percentage of screen height
double percentageChange = (double) (Math.abs(oldHeight - height) * 100) / screenHeight;
return percentageChange > PERCENTAGE_CHANGE_THRESHOLD;
}
}