11package com .capacitorjs .plugins .keyboard ;
22
33import android .content .Context ;
4- import android .graphics .Insets ;
5- import android .graphics .Point ;
64import android .graphics .Rect ;
7- import android .os .Build ;
85import android .util .DisplayMetrics ;
9- import android .view .Display ;
106import android .view .View ;
11- import android .view .ViewTreeObserver ;
127import android .view .Window ;
13- import android .view .WindowInsets ;
148import android .view .inputmethod .InputMethodManager ;
159import android .widget .FrameLayout ;
10+ import androidx .annotation .NonNull ;
1611import androidx .annotation .Nullable ;
1712import androidx .appcompat .app .AppCompatActivity ;
18- import com .getcapacitor .Logger ;
13+ import androidx .core .view .ViewCompat ;
14+ import androidx .core .view .WindowInsetsAnimationCompat ;
15+ import androidx .core .view .WindowInsetsCompat ;
16+ import java .util .List ;
1917
2018public class Keyboard {
2119
@@ -24,16 +22,10 @@ interface KeyboardEventListener {
2422 }
2523
2624 private AppCompatActivity activity ;
27- private ViewTreeObserver .OnGlobalLayoutListener list ;
2825 private View rootView ;
29- private View mChildOfContent ;
3026 private int usableHeightPrevious ;
3127 private FrameLayout .LayoutParams frameLayoutParams ;
32-
33- @ Nullable
34- public KeyboardEventListener getKeyboardEventListener () {
35- return keyboardEventListener ;
36- }
28+ private View mChildOfContent ;
3729
3830 public void setKeyboardEventListener (@ Nullable KeyboardEventListener keyboardEventListener ) {
3931 this .keyboardEventListener = keyboardEventListener ;
@@ -49,117 +41,69 @@ public void setKeyboardEventListener(@Nullable KeyboardEventListener keyboardEve
4941
5042 public Keyboard (AppCompatActivity activity , boolean resizeOnFullScreen ) {
5143 this .activity = activity ;
52- //calculate density-independent pixels (dp)
53- //http://developer.android.com/guide/practices/screens_support.html
54- DisplayMetrics dm = activity .getResources ().getDisplayMetrics ();
55- final float density = dm .density ;
5644
5745 //http://stackoverflow.com/a/4737265/1091751 detect if keyboard is showing
5846 FrameLayout content = activity .getWindow ().getDecorView ().findViewById (android .R .id .content );
5947 rootView = content .getRootView ();
60- list =
61- new ViewTreeObserver .OnGlobalLayoutListener () {
62- int previousHeightDiff = 0 ;
6348
49+ ViewCompat .setWindowInsetsAnimationCallback (
50+ rootView ,
51+ new WindowInsetsAnimationCompat .Callback (WindowInsetsAnimationCompat .Callback .DISPATCH_MODE_STOP ) {
52+ @ NonNull
6453 @ Override
65- public void onGlobalLayout () {
66- Rect r = new Rect ();
67- //r will be populated with the coordinates of your view that area still visible.
68- rootView .getWindowVisibleDisplayFrame (r );
69-
70- // cache properties for later use
71- int rootViewHeight = rootView .getRootView ().getHeight ();
72- int resultBottom = r .bottom ;
73- int screenHeight ;
74-
75- if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .R ) {
76- Insets windowInsets = rootView .getRootWindowInsets ().getInsetsIgnoringVisibility (WindowInsets .Type .systemBars ());
77- screenHeight = rootViewHeight ;
78- resultBottom = resultBottom + windowInsets .bottom ;
79- } else if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .M ) {
80- WindowInsets windowInsets = rootView .getRootWindowInsets ();
81- int stableInsetBottom = getLegacyStableInsetBottom (windowInsets );
82- screenHeight = rootViewHeight ;
83- resultBottom = resultBottom + stableInsetBottom ;
84- } else {
85- Point size = getLegacySizePoint ();
86- screenHeight = size .y ;
87- }
54+ public WindowInsetsCompat onProgress (
55+ @ NonNull WindowInsetsCompat insets ,
56+ @ NonNull List <WindowInsetsAnimationCompat > runningAnimations
57+ ) {
58+ return insets ;
59+ }
8860
89- int heightDiff = screenHeight - resultBottom ;
90-
91- int pixelHeightDiff = (int ) (heightDiff / density );
92-
93- if (pixelHeightDiff > 100 && pixelHeightDiff != previousHeightDiff ) { // if more than 100 pixels, its probably a keyboard...
94- if (resizeOnFullScreen ) {
95- possiblyResizeChildOfContent (true );
96- }
97-
98- if (keyboardEventListener != null ) {
99- keyboardEventListener .onKeyboardEvent (EVENT_KB_WILL_SHOW , pixelHeightDiff );
100- keyboardEventListener .onKeyboardEvent (EVENT_KB_DID_SHOW , pixelHeightDiff );
101- } else {
102- Logger .warn ("Native Keyboard Event Listener not found" );
103- }
104- } else if (pixelHeightDiff != previousHeightDiff && (previousHeightDiff - pixelHeightDiff ) > 100 ) {
105- if (resizeOnFullScreen ) {
106- possiblyResizeChildOfContent (false );
107- }
108-
109- if (keyboardEventListener != null ) {
110- keyboardEventListener .onKeyboardEvent (EVENT_KB_WILL_HIDE , 0 );
111- keyboardEventListener .onKeyboardEvent (EVENT_KB_DID_HIDE , 0 );
112- } else {
113- Logger .warn ("Native Keyboard Event Listener not found" );
114- }
61+ @ NonNull
62+ @ Override
63+ public WindowInsetsAnimationCompat .BoundsCompat onStart (
64+ @ NonNull WindowInsetsAnimationCompat animation ,
65+ @ NonNull WindowInsetsAnimationCompat .BoundsCompat bounds
66+ ) {
67+ boolean showingKeyboard = ViewCompat .getRootWindowInsets (rootView ).isVisible (WindowInsetsCompat .Type .ime ());
68+ WindowInsetsCompat insets = ViewCompat .getRootWindowInsets (rootView );
69+ int imeHeight = insets .getInsets (WindowInsetsCompat .Type .ime ()).bottom ;
70+ DisplayMetrics dm = activity .getResources ().getDisplayMetrics ();
71+ final float density = dm .density ;
72+
73+ if (resizeOnFullScreen ) {
74+ possiblyResizeChildOfContent (showingKeyboard );
11575 }
116- previousHeightDiff = pixelHeightDiff ;
117- }
11876
119- private void possiblyResizeChildOfContent (boolean keyboardShown ) {
120- int usableHeightNow = keyboardShown ? computeUsableHeight () : -1 ;
121- if (usableHeightPrevious != usableHeightNow ) {
122- frameLayoutParams .height = usableHeightNow ;
123- mChildOfContent .requestLayout ();
124- usableHeightPrevious = usableHeightNow ;
77+ if (showingKeyboard ) {
78+ keyboardEventListener .onKeyboardEvent (EVENT_KB_WILL_SHOW , Math .round (imeHeight / density ));
79+ } else {
80+ keyboardEventListener .onKeyboardEvent (EVENT_KB_WILL_HIDE , 0 );
12581 }
82+ return super .onStart (animation , bounds );
12683 }
12784
128- private int computeUsableHeight () {
129- Rect r = new Rect ();
130- mChildOfContent .getWindowVisibleDisplayFrame (r );
131- return isOverlays () ? r .bottom : r .height ();
85+ @ Override
86+ public void onEnd (@ NonNull WindowInsetsAnimationCompat animation ) {
87+ super .onEnd (animation );
88+ boolean showingKeyboard = ViewCompat .getRootWindowInsets (rootView ).isVisible (WindowInsetsCompat .Type .ime ());
89+ WindowInsetsCompat insets = ViewCompat .getRootWindowInsets (rootView );
90+ int imeHeight = insets .getInsets (WindowInsetsCompat .Type .ime ()).bottom ;
91+ DisplayMetrics dm = activity .getResources ().getDisplayMetrics ();
92+ final float density = dm .density ;
93+
94+ if (showingKeyboard ) {
95+ keyboardEventListener .onKeyboardEvent (EVENT_KB_DID_SHOW , Math .round (imeHeight / density ));
96+ } else {
97+ keyboardEventListener .onKeyboardEvent (EVENT_KB_DID_HIDE , 0 );
98+ }
13299 }
100+ }
101+ );
133102
134- @ SuppressWarnings ("deprecation" )
135- private boolean isOverlays () {
136- final Window window = activity .getWindow ();
137- return (
138- (window .getDecorView ().getSystemUiVisibility () & View .SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN ) ==
139- View .SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
140- );
141- }
142- };
143103 mChildOfContent = content .getChildAt (0 );
144- rootView .getViewTreeObserver ().addOnGlobalLayoutListener (list );
145104 frameLayoutParams = (FrameLayout .LayoutParams ) mChildOfContent .getLayoutParams ();
146105 }
147106
148- @ SuppressWarnings ("deprecation" )
149- private int getLegacyStableInsetBottom (WindowInsets windowInsets ) {
150- return windowInsets .getStableInsetBottom ();
151- }
152-
153- @ SuppressWarnings ("deprecation" )
154- private Point getLegacySizePoint () {
155- // calculate screen height differently for android versions <23: Lollipop 5.x, Marshmallow 6.x
156- //http://stackoverflow.com/a/29257533/3642890 beware of nexus 5
157- Display display = activity .getWindowManager ().getDefaultDisplay ();
158- Point size = new Point ();
159- display .getSize (size );
160- return size ;
161- }
162-
163107 public void show () {
164108 ((InputMethodManager ) activity .getSystemService (Context .INPUT_METHOD_SERVICE )).showSoftInput (activity .getCurrentFocus (), 0 );
165109 }
@@ -174,4 +118,27 @@ public boolean hide() {
174118 return true ;
175119 }
176120 }
121+
122+ private void possiblyResizeChildOfContent (boolean keyboardShown ) {
123+ int usableHeightNow = keyboardShown ? computeUsableHeight () : -1 ;
124+ if (usableHeightPrevious != usableHeightNow ) {
125+ frameLayoutParams .height = usableHeightNow ;
126+ mChildOfContent .requestLayout ();
127+ usableHeightPrevious = usableHeightNow ;
128+ }
129+ }
130+
131+ private int computeUsableHeight () {
132+ Rect r = new Rect ();
133+ mChildOfContent .getWindowVisibleDisplayFrame (r );
134+ return isOverlays () ? r .bottom : r .height ();
135+ }
136+
137+ @ SuppressWarnings ("deprecation" )
138+ private boolean isOverlays () {
139+ final Window window = activity .getWindow ();
140+ return (
141+ (window .getDecorView ().getSystemUiVisibility () & View .SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN ) == View .SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
142+ );
143+ }
177144}
0 commit comments