Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(android): parity for keyboardframechanged and keyboardVisible #13726

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.appcelerator.kroll.common.Log;
import org.appcelerator.titanium.ITiAppInfo;
import org.appcelerator.titanium.TiApplication;
import org.appcelerator.titanium.TiBaseActivity;
import org.appcelerator.titanium.TiC;
import org.appcelerator.titanium.util.TiConvert;
import org.appcelerator.titanium.util.TiSensorHelper;
Expand Down Expand Up @@ -155,6 +156,16 @@ public boolean getAccessibilityEnabled()
return TiApplication.getInstance().getAccessibilityManager().isEnabled();
}

@Kroll.getProperty
public boolean getKeyboardVisible()
{
TiBaseActivity activity = (TiBaseActivity) TiApplication.getAppCurrentActivity();
if (activity == null) {
return false;
}
return TiConvert.toBoolean(activity.keyboardVisible, false);
}

@Kroll.method(name = "_restart")
public void restart()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,21 @@ public void removeAppEventProxy(KrollProxy appEventProxy)
appEventProxies.remove(appEventProxy);
}

public boolean hasListener(String eventName)
{
for (WeakReference<KrollProxy> weakProxy : appEventProxies) {
KrollProxy appEventProxy = weakProxy.get();
if (appEventProxy == null) {
continue;
}
if (appEventProxy.hasListeners(eventName)) {
return true;
}

}
return false;
}

public boolean fireAppEvent(String eventName, KrollDict data)
{
boolean handled = false;
Expand All @@ -679,7 +694,6 @@ public boolean fireAppEvent(String eventName, KrollDict data)
if (appEventProxy == null) {
continue;
}

boolean proxyHandled = appEventProxy.fireEvent(eventName, data);
handled = handled || proxyHandled;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Insets;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.Build;
Expand Down Expand Up @@ -106,6 +107,7 @@ public abstract class TiBaseActivity extends AppCompatActivity implements TiActi
private TiActionBarStyleHandler actionBarStyleHandler;
private TiActivitySafeAreaMonitor safeAreaMonitor;
private Context baseContext;
public boolean keyboardVisible = false;
/**
* Callback to be invoked when the TiBaseActivity.onRequestPermissionsResult() has been called,
* providing the results of a requestPermissions() call. Instances of this interface are to
Expand Down Expand Up @@ -674,7 +676,11 @@ protected void onCreate(Bundle savedInstanceState)

this.inForeground = true;
this.launchIntent = getIntent();
this.safeAreaMonitor = new TiActivitySafeAreaMonitor(this);

TiApplication tiApp = getTiApp();
TiApplication.addToActivityStack(this);

this.safeAreaMonitor = new TiActivitySafeAreaMonitor(this, tiApp);

// Fetch the current UI mode flags. Used to determine light/dark theme being used.
Configuration config = getResources().getConfiguration();
Expand All @@ -695,9 +701,6 @@ protected void onCreate(Bundle savedInstanceState)
}
}

TiApplication tiApp = getTiApp();
TiApplication.addToActivityStack(this);

// Increment the Titanium activity reference count. To be decremented in onDestroy() method.
// Titanium's JavaScript runtime is created when we have at least 1 activity and destroyed when we have 0.
KrollRuntime.incrementActivityRefCount();
Expand Down Expand Up @@ -787,6 +790,34 @@ public void onChanged(TiActivitySafeAreaMonitor monitor)
windowProxy.fireSafeAreaChangedEvent();
}
}

@Override
public void onKeyboardChanged(boolean isVisible, int width, int height, Insets keyboardSize)
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
&& isVisible != keyboardVisible
&& tiApp != null
&& tiApp.hasListener("keyboardframechanged")) {
hansemannn marked this conversation as resolved.
Show resolved Hide resolved
KrollDict kdAll = new KrollDict();
KrollDict kdFrame = new KrollDict();

KrollDict kdX = new KrollDict();
kdX.put("left", keyboardSize.left);
kdX.put("right", keyboardSize.right);

KrollDict kdY = new KrollDict();
kdX.put("top", keyboardSize.top);
kdX.put("bottom", keyboardSize.bottom);
kdFrame.put("x", kdX);
kdFrame.put("y", kdY);
kdFrame.put("height", keyboardSize.bottom);
kdFrame.put("width", width - keyboardSize.left - keyboardSize.right);
kdAll.put("keyboardFrame", kdFrame);
kdAll.put("animationDuration", 0);
tiApp.fireAppEvent("keyboardframechanged", kdAll);
keyboardVisible = isVisible;
}
}
});
this.safeAreaMonitor.start();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,18 @@

package org.appcelerator.titanium.view;

import android.graphics.Insets;
import android.graphics.Rect;
import android.os.Build;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;

import android.view.View;
import android.view.Window;
import android.view.WindowInsets;

import org.appcelerator.titanium.TiApplication;

import java.util.ArrayList;

/** Tracks safe-area inset changes for a given activity. */
Expand All @@ -27,6 +32,7 @@ public class TiActivitySafeAreaMonitor
*/
public interface OnChangedListener {
void onChanged(TiActivitySafeAreaMonitor monitor);
void onKeyboardChanged(boolean keyboardVisible, int width, int height, Insets keyboardSize);
}

/** The activity to be monitored. */
Expand Down Expand Up @@ -68,18 +74,21 @@ public interface OnChangedListener {
/** Region between the screen insets in pixels, relative to the root decor view. */
private Rect safeArea;

private TiApplication tiApp;

/**
* Creates an object used to track safe-area region changes for the given activity.
* @param activity The activity to be monitored. Cannot be null.
*/
public TiActivitySafeAreaMonitor(AppCompatActivity activity)
public TiActivitySafeAreaMonitor(AppCompatActivity activity, TiApplication app)
{
// Validate.
if (activity == null) {
throw new NullPointerException();
}

// Initialize member variables.
this.tiApp = app;
this.activity = activity;
this.isActionBarAddedAsInset = true;
this.insetsProviderCollection = new ArrayList<>(8);
Expand All @@ -105,6 +114,17 @@ public void onLayoutChange(View view, int left, int top, int right, int bottom,
@Override
public WindowInsets onApplyWindowInsets(View view, WindowInsets insets)
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R
&& tiApp != null
&& tiApp.hasListener("keyboardframechanged")
) {
boolean keyboardVisible = insets.isVisible(WindowInsets.Type.ime());
Insets keyboardSize = insets.getInsets(WindowInsets.Type.ime());
if (changeListener != null && view != null) {
changeListener.onKeyboardChanged(keyboardVisible, view.getWidth(),
view.getHeight(), keyboardSize);
}
}
// Validate.
if (view == null) {
return insets;
Expand Down
14 changes: 10 additions & 4 deletions apidoc/Titanium/App/App.yml
Original file line number Diff line number Diff line change
Expand Up @@ -378,14 +378,17 @@ events:
summary: Fired when the soft keyboard is presented, on and off the screen.
description: |
This event fires when the application presents the soft keyboard on/off the screen . The
event returns the dictionary `keyboardFrame` containing `x`, `y`, `height` and `width` keys,
event on iOS returns the dictionary `keyboardFrame` containing `x`, `y`, `height` and `width` keys,
corresponding to the frame of the keyboard with respect to the screen coordinates.

On Titanium SDK 4.0.0 and later the event also contains a second parameter `animationDuration` representing
the duration of the animation for the presentation and dismissal of the soft keyboard.

Note that the keyboard `height` and `width` properties will not be accurate when the keyboard
is being dissmissed.

For Android it will only work using Android 11 and up. The return values are empty but you can use
`keyboardVisible` to check if the keyboard is visible or not.
properties:
- name: keyboardFrame
summary: A dictionary with keys x, y, width and height representing the frame of keyboard on screen.
Expand All @@ -394,8 +397,8 @@ events:
- name: animationDuration
summary: The duration of the keyboard animation. This parameter is only available on Titanium SDK 4.0.0 and later.
type: Number
platforms: [iphone, ipad, macos]
since: {iphone: "3.0.0", ipad: "3.0.0", macos: "9.2.0"}
platforms: [android, iphone, ipad, macos]
since: {android: "12.6.0", iphone: "3.0.0", ipad: "3.0.0", macos: "9.2.0"}

- name: significanttimechange
summary: Fired when there is a significant change in the time.
Expand Down Expand Up @@ -609,9 +612,12 @@ properties:

- name: keyboardVisible
summary: Indicates whether or not the soft keyboard is visible.
description: |
On Android it will only work using Android 11 and up. Otherwise it will always be false.
type: Boolean
permission: read-only
platforms: [iphone, ipad, macos]
since: {android: "12.6.0", iphone: "7.5.0", ipad: "7.5.0", macos: "9.2.0"}
platforms: [android, iphone, ipad, macos]

- name: trackUserInteraction
summary: Indicates whether or not the user interaction shoud be tracked.
Expand Down
Loading