diff options
| author | Po Lu | 2023-03-18 10:54:26 +0800 |
|---|---|---|
| committer | Po Lu | 2023-03-18 10:54:26 +0800 |
| commit | 634e3fcc20ea9fa5b1af59286f4b846a351f52c8 (patch) | |
| tree | 2a98eff1365c2776f53c163e58cd539d1a65ba87 /java | |
| parent | 773bdb15abd5527dfc27d811a70263ac10cf451b (diff) | |
| download | emacs-634e3fcc20ea9fa5b1af59286f4b846a351f52c8.tar.gz emacs-634e3fcc20ea9fa5b1af59286f4b846a351f52c8.zip | |
Update Android port
* java/org/gnu/emacs/EmacsView.java (EmacsView)
(prepareForLayout): New function. Call this prior to mapping
the view.
(onGlobalLayout): New function. Register as global layout
listener.
* java/org/gnu/emacs/EmacsWindow.java (EmacsWindow)
(notifyContentRectPosition): New function. Use specified
xPosition and yPosition when reporting the offsets of children
of the root window.
* java/org/gnu/emacs/EmacsWindowAttachmentManager.java
(registerWindow): Specify activity launch bounds if necessary.
* src/androidterm.c (handle_one_android_event): Send
MOVE_FRAME_EVENT where necessary.
Diffstat (limited to 'java')
| -rw-r--r-- | java/org/gnu/emacs/EmacsView.java | 30 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsWindow.java | 145 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsWindowAttachmentManager.java | 16 |
3 files changed, 128 insertions, 63 deletions
diff --git a/java/org/gnu/emacs/EmacsView.java b/java/org/gnu/emacs/EmacsView.java index 681da98fa16..88d17a255a2 100644 --- a/java/org/gnu/emacs/EmacsView.java +++ b/java/org/gnu/emacs/EmacsView.java | |||
| @@ -28,6 +28,7 @@ import android.view.View; | |||
| 28 | import android.view.KeyEvent; | 28 | import android.view.KeyEvent; |
| 29 | import android.view.MotionEvent; | 29 | import android.view.MotionEvent; |
| 30 | import android.view.ViewGroup; | 30 | import android.view.ViewGroup; |
| 31 | import android.view.ViewTreeObserver; | ||
| 31 | 32 | ||
| 32 | import android.view.inputmethod.EditorInfo; | 33 | import android.view.inputmethod.EditorInfo; |
| 33 | import android.view.inputmethod.InputConnection; | 34 | import android.view.inputmethod.InputConnection; |
| @@ -51,6 +52,7 @@ import android.util.Log; | |||
| 51 | It is also a ViewGroup, as it also lays out children. */ | 52 | It is also a ViewGroup, as it also lays out children. */ |
| 52 | 53 | ||
| 53 | public final class EmacsView extends ViewGroup | 54 | public final class EmacsView extends ViewGroup |
| 55 | implements ViewTreeObserver.OnGlobalLayoutListener | ||
| 54 | { | 56 | { |
| 55 | public static final String TAG = "EmacsView"; | 57 | public static final String TAG = "EmacsView"; |
| 56 | 58 | ||
| @@ -136,6 +138,9 @@ public final class EmacsView extends ViewGroup | |||
| 136 | context = getContext (); | 138 | context = getContext (); |
| 137 | tem = context.getSystemService (Context.INPUT_METHOD_SERVICE); | 139 | tem = context.getSystemService (Context.INPUT_METHOD_SERVICE); |
| 138 | imManager = (InputMethodManager) tem; | 140 | imManager = (InputMethodManager) tem; |
| 141 | |||
| 142 | /* Add this view as its own global layout listener. */ | ||
| 143 | getViewTreeObserver ().addOnGlobalLayoutListener (this); | ||
| 139 | } | 144 | } |
| 140 | 145 | ||
| 141 | private void | 146 | private void |
| @@ -238,6 +243,13 @@ public final class EmacsView extends ViewGroup | |||
| 238 | return canvas; | 243 | return canvas; |
| 239 | } | 244 | } |
| 240 | 245 | ||
| 246 | public void | ||
| 247 | prepareForLayout (int wantedWidth, int wantedHeight) | ||
| 248 | { | ||
| 249 | measuredWidth = wantedWidth; | ||
| 250 | measuredHeight = wantedWidth; | ||
| 251 | } | ||
| 252 | |||
| 241 | @Override | 253 | @Override |
| 242 | protected void | 254 | protected void |
| 243 | onMeasure (int widthMeasureSpec, int heightMeasureSpec) | 255 | onMeasure (int widthMeasureSpec, int heightMeasureSpec) |
| @@ -562,8 +574,7 @@ public final class EmacsView extends ViewGroup | |||
| 562 | bitmapDirty = true; | 574 | bitmapDirty = true; |
| 563 | 575 | ||
| 564 | /* Now expose the view contents again. */ | 576 | /* Now expose the view contents again. */ |
| 565 | EmacsNative.sendExpose (this.window.handle, 0, 0, | 577 | EmacsNative.sendExpose (this.window.handle, 0, 0, 0, 0); |
| 566 | measuredWidth, measuredHeight); | ||
| 567 | 578 | ||
| 568 | super.onAttachedToWindow (); | 579 | super.onAttachedToWindow (); |
| 569 | } | 580 | } |
| @@ -678,4 +689,19 @@ public final class EmacsView extends ViewGroup | |||
| 678 | { | 689 | { |
| 679 | return icMode; | 690 | return icMode; |
| 680 | } | 691 | } |
| 692 | |||
| 693 | @Override | ||
| 694 | public void | ||
| 695 | onGlobalLayout () | ||
| 696 | { | ||
| 697 | int[] locations; | ||
| 698 | |||
| 699 | /* Get the absolute offset of this view and specify its left and | ||
| 700 | top position in subsequent ConfigureNotify events. */ | ||
| 701 | |||
| 702 | locations = new int[2]; | ||
| 703 | getLocationInWindow (locations); | ||
| 704 | window.notifyContentRectPosition (locations[0], | ||
| 705 | locations[1]); | ||
| 706 | } | ||
| 681 | }; | 707 | }; |
diff --git a/java/org/gnu/emacs/EmacsWindow.java b/java/org/gnu/emacs/EmacsWindow.java index a8d1beedef7..c14bf16b96e 100644 --- a/java/org/gnu/emacs/EmacsWindow.java +++ b/java/org/gnu/emacs/EmacsWindow.java | |||
| @@ -133,6 +133,9 @@ public final class EmacsWindow extends EmacsHandleObject | |||
| 133 | creating new bitmaps. */ | 133 | creating new bitmaps. */ |
| 134 | public volatile int background; | 134 | public volatile int background; |
| 135 | 135 | ||
| 136 | /* The position of this window relative to the root window. */ | ||
| 137 | public int xPosition, yPosition; | ||
| 138 | |||
| 136 | public | 139 | public |
| 137 | EmacsWindow (short handle, final EmacsWindow parent, int x, int y, | 140 | EmacsWindow (short handle, final EmacsWindow parent, int x, int y, |
| 138 | int width, int height, boolean overrideRedirect) | 141 | int width, int height, boolean overrideRedirect) |
| @@ -192,18 +195,14 @@ public final class EmacsWindow extends EmacsHandleObject | |||
| 192 | background = pixel; | 195 | background = pixel; |
| 193 | } | 196 | } |
| 194 | 197 | ||
| 195 | public Rect | 198 | public synchronized Rect |
| 196 | getGeometry () | 199 | getGeometry () |
| 197 | { | 200 | { |
| 198 | synchronized (this) | 201 | return new Rect (rect); |
| 199 | { | ||
| 200 | /* Huh, this is it. */ | ||
| 201 | return rect; | ||
| 202 | } | ||
| 203 | } | 202 | } |
| 204 | 203 | ||
| 205 | @Override | 204 | @Override |
| 206 | public void | 205 | public synchronized void |
| 207 | destroyHandle () throws IllegalStateException | 206 | destroyHandle () throws IllegalStateException |
| 208 | { | 207 | { |
| 209 | if (parent != null) | 208 | if (parent != null) |
| @@ -258,22 +257,28 @@ public final class EmacsWindow extends EmacsHandleObject | |||
| 258 | return attached; | 257 | return attached; |
| 259 | } | 258 | } |
| 260 | 259 | ||
| 261 | public long | 260 | public synchronized long |
| 262 | viewLayout (int left, int top, int right, int bottom) | 261 | viewLayout (int left, int top, int right, int bottom) |
| 263 | { | 262 | { |
| 264 | int rectWidth, rectHeight; | 263 | int rectWidth, rectHeight; |
| 265 | 264 | ||
| 266 | synchronized (this) | 265 | rect.left = left; |
| 267 | { | 266 | rect.top = top; |
| 268 | rect.left = left; | 267 | rect.right = right; |
| 269 | rect.top = top; | 268 | rect.bottom = bottom; |
| 270 | rect.right = right; | ||
| 271 | rect.bottom = bottom; | ||
| 272 | } | ||
| 273 | 269 | ||
| 274 | rectWidth = right - left; | 270 | rectWidth = right - left; |
| 275 | rectHeight = bottom - top; | 271 | rectHeight = bottom - top; |
| 276 | 272 | ||
| 273 | /* If parent is null, use xPosition and yPosition instead of the | ||
| 274 | geometry rectangle positions. */ | ||
| 275 | |||
| 276 | if (parent == null) | ||
| 277 | { | ||
| 278 | left = xPosition; | ||
| 279 | top = yPosition; | ||
| 280 | } | ||
| 281 | |||
| 277 | return EmacsNative.sendConfigureNotify (this.handle, | 282 | return EmacsNative.sendConfigureNotify (this.handle, |
| 278 | System.currentTimeMillis (), | 283 | System.currentTimeMillis (), |
| 279 | left, top, rectWidth, | 284 | left, top, rectWidth, |
| @@ -283,8 +288,6 @@ public final class EmacsWindow extends EmacsHandleObject | |||
| 283 | public void | 288 | public void |
| 284 | requestViewLayout () | 289 | requestViewLayout () |
| 285 | { | 290 | { |
| 286 | /* This is necessary because otherwise subsequent drawing on the | ||
| 287 | Emacs thread may be lost. */ | ||
| 288 | view.explicitlyDirtyBitmap (); | 291 | view.explicitlyDirtyBitmap (); |
| 289 | 292 | ||
| 290 | EmacsService.SERVICE.runOnUiThread (new Runnable () { | 293 | EmacsService.SERVICE.runOnUiThread (new Runnable () { |
| @@ -302,35 +305,29 @@ public final class EmacsWindow extends EmacsHandleObject | |||
| 302 | }); | 305 | }); |
| 303 | } | 306 | } |
| 304 | 307 | ||
| 305 | public void | 308 | public synchronized void |
| 306 | resizeWindow (int width, int height) | 309 | resizeWindow (int width, int height) |
| 307 | { | 310 | { |
| 308 | synchronized (this) | 311 | rect.right = rect.left + width; |
| 309 | { | 312 | rect.bottom = rect.top + height; |
| 310 | rect.right = rect.left + width; | ||
| 311 | rect.bottom = rect.top + height; | ||
| 312 | 313 | ||
| 313 | requestViewLayout (); | 314 | requestViewLayout (); |
| 314 | } | ||
| 315 | } | 315 | } |
| 316 | 316 | ||
| 317 | public void | 317 | public synchronized void |
| 318 | moveWindow (int x, int y) | 318 | moveWindow (int x, int y) |
| 319 | { | 319 | { |
| 320 | int width, height; | 320 | int width, height; |
| 321 | 321 | ||
| 322 | synchronized (this) | 322 | width = rect.width (); |
| 323 | { | 323 | height = rect.height (); |
| 324 | width = rect.width (); | ||
| 325 | height = rect.height (); | ||
| 326 | 324 | ||
| 327 | rect.left = x; | 325 | rect.left = x; |
| 328 | rect.top = y; | 326 | rect.top = y; |
| 329 | rect.right = x + width; | 327 | rect.right = x + width; |
| 330 | rect.bottom = y + height; | 328 | rect.bottom = y + height; |
| 331 | 329 | ||
| 332 | requestViewLayout (); | 330 | requestViewLayout (); |
| 333 | } | ||
| 334 | } | 331 | } |
| 335 | 332 | ||
| 336 | private WindowManager.LayoutParams | 333 | private WindowManager.LayoutParams |
| @@ -366,13 +363,17 @@ public final class EmacsWindow extends EmacsHandleObject | |||
| 366 | return EmacsService.SERVICE; | 363 | return EmacsService.SERVICE; |
| 367 | } | 364 | } |
| 368 | 365 | ||
| 369 | public void | 366 | public synchronized void |
| 370 | mapWindow () | 367 | mapWindow () |
| 371 | { | 368 | { |
| 369 | final int width, height; | ||
| 370 | |||
| 372 | if (isMapped) | 371 | if (isMapped) |
| 373 | return; | 372 | return; |
| 374 | 373 | ||
| 375 | isMapped = true; | 374 | isMapped = true; |
| 375 | width = rect.width (); | ||
| 376 | height = rect.height (); | ||
| 376 | 377 | ||
| 377 | if (parent == null) | 378 | if (parent == null) |
| 378 | { | 379 | { |
| @@ -424,6 +425,7 @@ public final class EmacsWindow extends EmacsHandleObject | |||
| 424 | /* Attach the view. */ | 425 | /* Attach the view. */ |
| 425 | try | 426 | try |
| 426 | { | 427 | { |
| 428 | view.prepareForLayout (width, height); | ||
| 427 | windowManager.addView (view, params); | 429 | windowManager.addView (view, params); |
| 428 | 430 | ||
| 429 | /* Record the window manager being used in the | 431 | /* Record the window manager being used in the |
| @@ -448,10 +450,14 @@ public final class EmacsWindow extends EmacsHandleObject | |||
| 448 | public void | 450 | public void |
| 449 | run () | 451 | run () |
| 450 | { | 452 | { |
| 453 | /* Prior to mapping the view, set its measuredWidth and | ||
| 454 | measuredHeight to some reasonable value, in order to | ||
| 455 | avoid excessive bitmap dirtying. */ | ||
| 456 | |||
| 457 | view.prepareForLayout (width, height); | ||
| 451 | view.setVisibility (View.VISIBLE); | 458 | view.setVisibility (View.VISIBLE); |
| 452 | 459 | ||
| 453 | if (!getDontFocusOnMap ()) | 460 | if (!getDontFocusOnMap ()) |
| 454 | /* Eventually this should check no-focus-on-map. */ | ||
| 455 | view.requestFocus (); | 461 | view.requestFocus (); |
| 456 | } | 462 | } |
| 457 | }); | 463 | }); |
| @@ -512,12 +518,9 @@ public final class EmacsWindow extends EmacsHandleObject | |||
| 512 | public void | 518 | public void |
| 513 | clearWindow () | 519 | clearWindow () |
| 514 | { | 520 | { |
| 515 | synchronized (this) | 521 | EmacsService.SERVICE.fillRectangle (this, scratchGC, |
| 516 | { | 522 | 0, 0, rect.width (), |
| 517 | EmacsService.SERVICE.fillRectangle (this, scratchGC, | 523 | rect.height ()); |
| 518 | 0, 0, rect.width (), | ||
| 519 | rect.height ()); | ||
| 520 | } | ||
| 521 | } | 524 | } |
| 522 | 525 | ||
| 523 | public void | 526 | public void |
| @@ -1001,7 +1004,7 @@ public final class EmacsWindow extends EmacsHandleObject | |||
| 1001 | return false; | 1004 | return false; |
| 1002 | } | 1005 | } |
| 1003 | 1006 | ||
| 1004 | public void | 1007 | public synchronized void |
| 1005 | reparentTo (final EmacsWindow otherWindow, int x, int y) | 1008 | reparentTo (final EmacsWindow otherWindow, int x, int y) |
| 1006 | { | 1009 | { |
| 1007 | int width, height; | 1010 | int width, height; |
| @@ -1017,15 +1020,12 @@ public final class EmacsWindow extends EmacsHandleObject | |||
| 1017 | parent = otherWindow; | 1020 | parent = otherWindow; |
| 1018 | 1021 | ||
| 1019 | /* Move this window to the new location. */ | 1022 | /* Move this window to the new location. */ |
| 1020 | synchronized (this) | 1023 | width = rect.width (); |
| 1021 | { | 1024 | height = rect.height (); |
| 1022 | width = rect.width (); | 1025 | rect.left = x; |
| 1023 | height = rect.height (); | 1026 | rect.top = y; |
| 1024 | rect.left = x; | 1027 | rect.right = x + width; |
| 1025 | rect.top = y; | 1028 | rect.bottom = y + height; |
| 1026 | rect.right = x + width; | ||
| 1027 | rect.bottom = y + height; | ||
| 1028 | } | ||
| 1029 | 1029 | ||
| 1030 | /* Now do the work necessary on the UI thread to reparent the | 1030 | /* Now do the work necessary on the UI thread to reparent the |
| 1031 | window. */ | 1031 | window. */ |
| @@ -1081,7 +1081,7 @@ public final class EmacsWindow extends EmacsHandleObject | |||
| 1081 | }); | 1081 | }); |
| 1082 | } | 1082 | } |
| 1083 | 1083 | ||
| 1084 | public void | 1084 | public synchronized void |
| 1085 | raise () | 1085 | raise () |
| 1086 | { | 1086 | { |
| 1087 | /* This does nothing here. */ | 1087 | /* This does nothing here. */ |
| @@ -1103,7 +1103,7 @@ public final class EmacsWindow extends EmacsHandleObject | |||
| 1103 | }); | 1103 | }); |
| 1104 | } | 1104 | } |
| 1105 | 1105 | ||
| 1106 | public void | 1106 | public synchronized void |
| 1107 | lower () | 1107 | lower () |
| 1108 | { | 1108 | { |
| 1109 | /* This does nothing here. */ | 1109 | /* This does nothing here. */ |
| @@ -1125,17 +1125,15 @@ public final class EmacsWindow extends EmacsHandleObject | |||
| 1125 | }); | 1125 | }); |
| 1126 | } | 1126 | } |
| 1127 | 1127 | ||
| 1128 | public int[] | 1128 | public synchronized int[] |
| 1129 | getWindowGeometry () | 1129 | getWindowGeometry () |
| 1130 | { | 1130 | { |
| 1131 | int[] array; | 1131 | int[] array; |
| 1132 | Rect rect; | ||
| 1133 | 1132 | ||
| 1134 | array = new int[4]; | 1133 | array = new int[4]; |
| 1135 | rect = getGeometry (); | ||
| 1136 | 1134 | ||
| 1137 | array[0] = rect.left; | 1135 | array[0] = parent != null ? rect.left : xPosition; |
| 1138 | array[1] = rect.top; | 1136 | array[1] = parent != null ? rect.top : yPosition; |
| 1139 | array[2] = rect.width (); | 1137 | array[2] = rect.width (); |
| 1140 | array[3] = rect.height (); | 1138 | array[3] = rect.height (); |
| 1141 | 1139 | ||
| @@ -1272,4 +1270,31 @@ public final class EmacsWindow extends EmacsHandleObject | |||
| 1272 | } | 1270 | } |
| 1273 | }); | 1271 | }); |
| 1274 | } | 1272 | } |
| 1273 | |||
| 1274 | public synchronized void | ||
| 1275 | notifyContentRectPosition (int xPosition, int yPosition) | ||
| 1276 | { | ||
| 1277 | Rect geometry; | ||
| 1278 | |||
| 1279 | /* Ignore these notifications if not a child of the root | ||
| 1280 | window. */ | ||
| 1281 | if (parent != null) | ||
| 1282 | return; | ||
| 1283 | |||
| 1284 | /* xPosition and yPosition are the position of this window | ||
| 1285 | relative to the screen. Set them and request a ConfigureNotify | ||
| 1286 | event. */ | ||
| 1287 | |||
| 1288 | if (this.xPosition != xPosition | ||
| 1289 | || this.yPosition != yPosition) | ||
| 1290 | { | ||
| 1291 | this.xPosition = xPosition; | ||
| 1292 | this.yPosition = yPosition; | ||
| 1293 | |||
| 1294 | EmacsNative.sendConfigureNotify (this.handle, | ||
| 1295 | System.currentTimeMillis (), | ||
| 1296 | xPosition, yPosition, | ||
| 1297 | rect.width (), rect.height ()); | ||
| 1298 | } | ||
| 1299 | } | ||
| 1275 | }; | 1300 | }; |
diff --git a/java/org/gnu/emacs/EmacsWindowAttachmentManager.java b/java/org/gnu/emacs/EmacsWindowAttachmentManager.java index c0197ab802c..4fda48616f0 100644 --- a/java/org/gnu/emacs/EmacsWindowAttachmentManager.java +++ b/java/org/gnu/emacs/EmacsWindowAttachmentManager.java | |||
| @@ -22,7 +22,9 @@ package org.gnu.emacs; | |||
| 22 | import java.util.ArrayList; | 22 | import java.util.ArrayList; |
| 23 | import java.util.List; | 23 | import java.util.List; |
| 24 | 24 | ||
| 25 | import android.app.ActivityOptions; | ||
| 25 | import android.content.Intent; | 26 | import android.content.Intent; |
| 27 | import android.os.Build; | ||
| 26 | import android.util.Log; | 28 | import android.util.Log; |
| 27 | 29 | ||
| 28 | /* Code to paper over the differences in lifecycles between | 30 | /* Code to paper over the differences in lifecycles between |
| @@ -102,6 +104,7 @@ public final class EmacsWindowAttachmentManager | |||
| 102 | registerWindow (EmacsWindow window) | 104 | registerWindow (EmacsWindow window) |
| 103 | { | 105 | { |
| 104 | Intent intent; | 106 | Intent intent; |
| 107 | ActivityOptions options; | ||
| 105 | 108 | ||
| 106 | Log.d (TAG, "registerWindow (maybe): " + window); | 109 | Log.d (TAG, "registerWindow (maybe): " + window); |
| 107 | 110 | ||
| @@ -128,7 +131,18 @@ public final class EmacsWindowAttachmentManager | |||
| 128 | intent.addFlags (Intent.FLAG_ACTIVITY_NEW_DOCUMENT | 131 | intent.addFlags (Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
| 129 | | Intent.FLAG_ACTIVITY_NEW_TASK | 132 | | Intent.FLAG_ACTIVITY_NEW_TASK |
| 130 | | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); | 133 | | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); |
| 131 | EmacsService.SERVICE.startActivity (intent); | 134 | |
| 135 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) | ||
| 136 | EmacsService.SERVICE.startActivity (intent); | ||
| 137 | else | ||
| 138 | { | ||
| 139 | /* Specify the desired window size. */ | ||
| 140 | options = ActivityOptions.makeBasic (); | ||
| 141 | options.setLaunchBounds (window.getGeometry ()); | ||
| 142 | EmacsService.SERVICE.startActivity (intent, | ||
| 143 | options.toBundle ()); | ||
| 144 | } | ||
| 145 | |||
| 132 | Log.d (TAG, "registerWindow: startActivity"); | 146 | Log.d (TAG, "registerWindow: startActivity"); |
| 133 | } | 147 | } |
| 134 | 148 | ||