@capgo/capacitor-updater 8.49.0 → 8.49.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -137,7 +137,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
137
137
  static final int APPLICATION_EXIT_REASON_USER_REQUESTED = 10;
138
138
  static final int APPLICATION_EXIT_REASON_DEPENDENCY_DIED = 12;
139
139
 
140
- private final String pluginVersion = "8.49.0";
140
+ private final String pluginVersion = "8.49.1";
141
141
  private static final String DELAY_CONDITION_PREFERENCES = "";
142
142
 
143
143
  private SharedPreferences.Editor editor;
@@ -6,13 +6,22 @@
6
6
 
7
7
  package ee.forgr.capacitor_updater;
8
8
 
9
+ import android.view.ActionMode;
10
+ import android.view.KeyEvent;
11
+ import android.view.KeyboardShortcutGroup;
12
+ import android.view.Menu;
13
+ import android.view.MenuItem;
9
14
  import android.view.MotionEvent;
15
+ import android.view.SearchEvent;
10
16
  import android.view.View;
11
- import com.getcapacitor.Bridge;
17
+ import android.view.Window;
18
+ import android.view.WindowManager;
19
+ import android.view.accessibility.AccessibilityEvent;
12
20
  import com.getcapacitor.BridgeActivity;
13
- import java.lang.reflect.Field;
21
+ import java.lang.ref.WeakReference;
22
+ import java.util.List;
14
23
 
15
- public class ThreeFingerPinchDetector implements View.OnTouchListener {
24
+ public class ThreeFingerPinchDetector {
16
25
 
17
26
  public interface Listener {
18
27
  void onThreeFingerPinchDetected();
@@ -24,9 +33,10 @@ public class ThreeFingerPinchDetector implements View.OnTouchListener {
24
33
 
25
34
  private final Listener listener;
26
35
  private final Logger logger;
27
- private View targetView;
28
- private View.OnTouchListener previousOnTouchListener;
29
- private boolean touchListenerInstalled = false;
36
+ private Window targetWindow;
37
+ private Window.Callback previousWindowCallback;
38
+ private Window.Callback windowCallback;
39
+ private WeakReference<ThreeFingerPinchDetector> detectorReference;
30
40
  private float initialSpan = 0;
31
41
  private boolean tracking = false;
32
42
  private boolean triggered = false;
@@ -38,74 +48,68 @@ public class ThreeFingerPinchDetector implements View.OnTouchListener {
38
48
  }
39
49
 
40
50
  public void start(BridgeActivity activity) {
41
- if (targetView != null) {
51
+ if (targetWindow != null) {
42
52
  stop();
43
53
  }
44
54
 
45
- View view = null;
46
- Bridge bridge = activity.getBridge();
47
- if (bridge != null && bridge.getWebView() != null) {
48
- view = bridge.getWebView();
49
- }
50
- if (view == null && activity.getWindow() != null) {
51
- view = activity.getWindow().getDecorView().getRootView();
52
- }
53
- if (view == null) {
54
- logger.warn("Three finger pinch detector could not find a target view");
55
+ Window window = activity.getWindow();
56
+ if (window == null) {
57
+ logger.warn("Three finger pinch detector could not find a target window");
55
58
  return;
56
59
  }
57
60
 
58
- this.targetView = view;
59
- this.previousOnTouchListener = getCurrentOnTouchListener(view);
60
- if (this.previousOnTouchListener != this) {
61
- this.targetView.setOnTouchListener(this);
62
- this.touchListenerInstalled = true;
63
- }
61
+ this.targetWindow = window;
62
+ this.previousWindowCallback = window.getCallback();
63
+ this.detectorReference = new WeakReference<>(this);
64
+ this.windowCallback = new PinchWindowCallback(this.previousWindowCallback, this.detectorReference);
65
+ window.setCallback(this.windowCallback);
66
+ logger.info("Three finger pinch detector installed on activity window");
64
67
  }
65
68
 
66
69
  public void stop() {
67
- if (targetView != null) {
68
- View.OnTouchListener currentOnTouchListener = getCurrentOnTouchListener(targetView);
69
- if (touchListenerInstalled && (currentOnTouchListener == this || currentOnTouchListener == null)) {
70
- targetView.setOnTouchListener(previousOnTouchListener);
70
+ if (targetWindow != null) {
71
+ if (windowCallback instanceof PinchWindowCallback) {
72
+ ((PinchWindowCallback) windowCallback).disable();
71
73
  }
72
- targetView = null;
73
- previousOnTouchListener = null;
74
- touchListenerInstalled = false;
74
+ if (detectorReference != null) {
75
+ detectorReference.clear();
76
+ }
77
+ if (targetWindow.getCallback() == windowCallback) {
78
+ targetWindow.setCallback(previousWindowCallback);
79
+ }
80
+ targetWindow = null;
81
+ previousWindowCallback = null;
82
+ windowCallback = null;
83
+ detectorReference = null;
75
84
  }
76
85
  reset();
77
86
  }
78
87
 
79
- @Override
80
- public boolean onTouch(View view, MotionEvent event) {
81
- boolean consumedByPreviousListener = false;
82
- if (previousOnTouchListener != null && previousOnTouchListener != this) {
83
- consumedByPreviousListener = previousOnTouchListener.onTouch(view, event);
84
- }
85
-
88
+ private void handleTouch(MotionEvent event) {
86
89
  int action = event.getActionMasked();
87
90
  if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP) {
88
91
  reset();
89
- return consumedByPreviousListener;
92
+ return;
90
93
  }
91
94
 
92
95
  if (event.getPointerCount() != REQUIRED_POINTER_COUNT) {
93
96
  if (action == MotionEvent.ACTION_POINTER_DOWN) {
94
97
  reset();
95
98
  }
96
- return consumedByPreviousListener;
99
+ return;
97
100
  }
98
101
 
99
102
  float span = calculateSpan(event);
100
103
  if (span <= 0) {
101
- return consumedByPreviousListener;
104
+ return;
102
105
  }
103
106
 
104
107
  if (!tracking || action == MotionEvent.ACTION_POINTER_DOWN) {
105
108
  initialSpan = span;
106
109
  tracking = true;
107
110
  triggered = false;
108
- return consumedByPreviousListener;
111
+ logger.info("Three finger pinch tracking started");
112
+ return;
109
113
  }
110
114
 
111
115
  if (!triggered && Math.abs(span - initialSpan) / initialSpan >= MIN_SCALE_DELTA) {
@@ -113,13 +117,12 @@ public class ThreeFingerPinchDetector implements View.OnTouchListener {
113
117
  if (currentTime - lastPinchTime > PINCH_TIMEOUT) {
114
118
  triggered = true;
115
119
  lastPinchTime = currentTime;
120
+ logger.info("Three finger pinch threshold reached");
116
121
  if (listener != null) {
117
122
  listener.onThreeFingerPinchDetected();
118
123
  }
119
124
  }
120
125
  }
121
-
122
- return consumedByPreviousListener;
123
126
  }
124
127
 
125
128
  private float calculateSpan(MotionEvent event) {
@@ -141,29 +144,180 @@ public class ThreeFingerPinchDetector implements View.OnTouchListener {
141
144
  return totalDistance / REQUIRED_POINTER_COUNT;
142
145
  }
143
146
 
144
- private View.OnTouchListener getCurrentOnTouchListener(View view) {
145
- try {
146
- Field listenerInfoField = View.class.getDeclaredField("mListenerInfo");
147
- listenerInfoField.setAccessible(true);
148
- Object listenerInfo = listenerInfoField.get(view);
149
- if (listenerInfo == null) {
150
- return null;
151
- }
152
- Field onTouchListenerField = listenerInfo.getClass().getDeclaredField("mOnTouchListener");
153
- onTouchListenerField.setAccessible(true);
154
- Object listener = onTouchListenerField.get(listenerInfo);
155
- if (listener instanceof View.OnTouchListener) {
156
- return (View.OnTouchListener) listener;
157
- }
158
- } catch (ReflectiveOperationException | RuntimeException exception) {
159
- logger.warn("Three finger pinch detector could not inspect the current touch listener: " + exception.getMessage());
160
- }
161
- return null;
162
- }
163
-
164
147
  private void reset() {
165
148
  initialSpan = 0;
166
149
  tracking = false;
167
150
  triggered = false;
168
151
  }
152
+
153
+ private static class PinchWindowCallback implements Window.Callback {
154
+
155
+ private final Window.Callback delegate;
156
+ private final WeakReference<ThreeFingerPinchDetector> detectorReference;
157
+ private boolean enabled = true;
158
+
159
+ PinchWindowCallback(Window.Callback delegate, WeakReference<ThreeFingerPinchDetector> detectorReference) {
160
+ this.delegate = delegate;
161
+ this.detectorReference = detectorReference;
162
+ }
163
+
164
+ void disable() {
165
+ enabled = false;
166
+ if (detectorReference != null) {
167
+ detectorReference.clear();
168
+ }
169
+ }
170
+
171
+ @Override
172
+ public boolean dispatchKeyEvent(KeyEvent event) {
173
+ return delegate != null && delegate.dispatchKeyEvent(event);
174
+ }
175
+
176
+ @Override
177
+ public boolean dispatchKeyShortcutEvent(KeyEvent event) {
178
+ return delegate != null && delegate.dispatchKeyShortcutEvent(event);
179
+ }
180
+
181
+ @Override
182
+ public boolean dispatchTouchEvent(MotionEvent event) {
183
+ boolean handled = delegate != null && delegate.dispatchTouchEvent(event);
184
+ if (enabled) {
185
+ ThreeFingerPinchDetector detector = detectorReference == null ? null : detectorReference.get();
186
+ if (detector != null) {
187
+ detector.handleTouch(event);
188
+ }
189
+ }
190
+ return handled;
191
+ }
192
+
193
+ @Override
194
+ public boolean dispatchTrackballEvent(MotionEvent event) {
195
+ return delegate != null && delegate.dispatchTrackballEvent(event);
196
+ }
197
+
198
+ @Override
199
+ public boolean dispatchGenericMotionEvent(MotionEvent event) {
200
+ return delegate != null && delegate.dispatchGenericMotionEvent(event);
201
+ }
202
+
203
+ @Override
204
+ public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
205
+ return delegate != null && delegate.dispatchPopulateAccessibilityEvent(event);
206
+ }
207
+
208
+ @Override
209
+ public View onCreatePanelView(int featureId) {
210
+ return delegate == null ? null : delegate.onCreatePanelView(featureId);
211
+ }
212
+
213
+ @Override
214
+ public boolean onCreatePanelMenu(int featureId, Menu menu) {
215
+ return delegate != null && delegate.onCreatePanelMenu(featureId, menu);
216
+ }
217
+
218
+ @Override
219
+ public boolean onPreparePanel(int featureId, View view, Menu menu) {
220
+ return delegate != null && delegate.onPreparePanel(featureId, view, menu);
221
+ }
222
+
223
+ @Override
224
+ public boolean onMenuOpened(int featureId, Menu menu) {
225
+ return delegate != null && delegate.onMenuOpened(featureId, menu);
226
+ }
227
+
228
+ @Override
229
+ public boolean onMenuItemSelected(int featureId, MenuItem item) {
230
+ return delegate != null && delegate.onMenuItemSelected(featureId, item);
231
+ }
232
+
233
+ @Override
234
+ public void onWindowAttributesChanged(WindowManager.LayoutParams attrs) {
235
+ if (delegate != null) {
236
+ delegate.onWindowAttributesChanged(attrs);
237
+ }
238
+ }
239
+
240
+ @Override
241
+ public void onContentChanged() {
242
+ if (delegate != null) {
243
+ delegate.onContentChanged();
244
+ }
245
+ }
246
+
247
+ @Override
248
+ public void onWindowFocusChanged(boolean hasFocus) {
249
+ if (delegate != null) {
250
+ delegate.onWindowFocusChanged(hasFocus);
251
+ }
252
+ }
253
+
254
+ @Override
255
+ public void onAttachedToWindow() {
256
+ if (delegate != null) {
257
+ delegate.onAttachedToWindow();
258
+ }
259
+ }
260
+
261
+ @Override
262
+ public void onDetachedFromWindow() {
263
+ if (delegate != null) {
264
+ delegate.onDetachedFromWindow();
265
+ }
266
+ }
267
+
268
+ @Override
269
+ public void onPanelClosed(int featureId, Menu menu) {
270
+ if (delegate != null) {
271
+ delegate.onPanelClosed(featureId, menu);
272
+ }
273
+ }
274
+
275
+ @Override
276
+ public boolean onSearchRequested() {
277
+ return delegate != null && delegate.onSearchRequested();
278
+ }
279
+
280
+ @Override
281
+ public boolean onSearchRequested(SearchEvent searchEvent) {
282
+ return delegate != null && delegate.onSearchRequested(searchEvent);
283
+ }
284
+
285
+ @Override
286
+ public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) {
287
+ return delegate == null ? null : delegate.onWindowStartingActionMode(callback);
288
+ }
289
+
290
+ @Override
291
+ public ActionMode onWindowStartingActionMode(ActionMode.Callback callback, int type) {
292
+ return delegate == null ? null : delegate.onWindowStartingActionMode(callback, type);
293
+ }
294
+
295
+ @Override
296
+ public void onActionModeStarted(ActionMode mode) {
297
+ if (delegate != null) {
298
+ delegate.onActionModeStarted(mode);
299
+ }
300
+ }
301
+
302
+ @Override
303
+ public void onActionModeFinished(ActionMode mode) {
304
+ if (delegate != null) {
305
+ delegate.onActionModeFinished(mode);
306
+ }
307
+ }
308
+
309
+ @Override
310
+ public void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, Menu menu, int deviceId) {
311
+ if (delegate != null) {
312
+ delegate.onProvideKeyboardShortcuts(data, menu, deviceId);
313
+ }
314
+ }
315
+
316
+ @Override
317
+ public void onPointerCaptureChanged(boolean hasCapture) {
318
+ if (delegate != null) {
319
+ delegate.onPointerCaptureChanged(hasCapture);
320
+ }
321
+ }
322
+ }
169
323
  }
@@ -85,7 +85,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
85
85
  CAPPluginMethod(name: "completeFlexibleUpdate", returnType: CAPPluginReturnPromise)
86
86
  ]
87
87
  public var implementation = CapgoUpdater()
88
- private let pluginVersion: String = "8.49.0"
88
+ private let pluginVersion: String = "8.49.1"
89
89
  static let updateUrlDefault = "https://plugin.capgo.app/updates"
90
90
  static let statsUrlDefault = "https://plugin.capgo.app/stats"
91
91
  static let channelUrlDefault = "https://plugin.capgo.app/channel_self"
@@ -14,10 +14,11 @@ private let threeFingerPinchScaleDelta: CGFloat = 0.12
14
14
  final class ThreeFingerPinchGestureRecognizer: UIGestureRecognizer {
15
15
  private var initialSpan: CGFloat = 0
16
16
  private(set) var scale: CGFloat = 1
17
+ var onTrackingStarted: (() -> Void)?
17
18
 
18
19
  override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
19
20
  super.touchesBegan(touches, with: event)
20
- guard let view = self.view, let activeTouches = activeTouches(in: view, with: event), activeTouches.count <= 3 else {
21
+ guard let view = self.view, let activeTouches = activeTouches(with: event), activeTouches.count <= 3 else {
21
22
  self.state = .failed
22
23
  return
23
24
  }
@@ -25,14 +26,18 @@ final class ThreeFingerPinchGestureRecognizer: UIGestureRecognizer {
25
26
  if activeTouches.count == 3 {
26
27
  self.initialSpan = span(for: activeTouches, in: view)
27
28
  self.scale = 1
28
- self.state = self.initialSpan > 0 ? .began : .failed
29
+ if self.initialSpan > 0 {
30
+ self.onTrackingStarted?()
31
+ } else {
32
+ self.state = .failed
33
+ }
29
34
  }
30
35
  }
31
36
 
32
37
  override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
33
38
  super.touchesMoved(touches, with: event)
34
39
  guard let view = self.view,
35
- let activeTouches = activeTouches(in: view, with: event),
40
+ let activeTouches = activeTouches(with: event),
36
41
  activeTouches.count == 3,
37
42
  self.initialSpan > 0 else {
38
43
  self.state = .failed
@@ -40,12 +45,16 @@ final class ThreeFingerPinchGestureRecognizer: UIGestureRecognizer {
40
45
  }
41
46
 
42
47
  self.scale = span(for: activeTouches, in: view) / self.initialSpan
43
- self.state = .changed
48
+ if abs(self.scale - 1) >= threeFingerPinchScaleDelta {
49
+ self.state = .recognized
50
+ }
44
51
  }
45
52
 
46
53
  override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent) {
47
54
  super.touchesEnded(touches, with: event)
48
- self.state = self.state == .possible || self.state == .began ? .failed : .ended
55
+ if self.state == .possible {
56
+ self.state = .failed
57
+ }
49
58
  }
50
59
 
51
60
  override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent) {
@@ -59,8 +68,8 @@ final class ThreeFingerPinchGestureRecognizer: UIGestureRecognizer {
59
68
  self.scale = 1
60
69
  }
61
70
 
62
- private func activeTouches(in view: UIView, with event: UIEvent) -> [UITouch]? {
63
- event.touches(for: view)?.filter { touch in
71
+ private func activeTouches(with event: UIEvent) -> [UITouch]? {
72
+ event.touches(for: self)?.filter { touch in
64
73
  touch.phase != .ended && touch.phase != .cancelled
65
74
  }
66
75
  }
@@ -106,7 +115,7 @@ extension CapacitorUpdaterPlugin: UIGestureRecognizerDelegate {
106
115
  let shouldInstall = self.shakeMenuGesture == Self.shakeMenuGestureThreeFingerPinch &&
107
116
  (self.shakeMenuEnabled || self.shakeChannelSelectorEnabled)
108
117
 
109
- guard shouldInstall, let targetView = self.bridge?.webView ?? self.bridge?.viewController?.view else {
118
+ guard shouldInstall, let targetView = self.bridge?.viewController?.view ?? self.bridge?.webView else {
110
119
  self.removeShakeMenuGestureRecognizer()
111
120
  return
112
121
  }
@@ -122,6 +131,9 @@ extension CapacitorUpdaterPlugin: UIGestureRecognizerDelegate {
122
131
  recognizer.delaysTouchesBegan = false
123
132
  recognizer.delaysTouchesEnded = false
124
133
  recognizer.delegate = self
134
+ recognizer.onTrackingStarted = { [weak self] in
135
+ self?.logger.info("Three finger pinch tracking started")
136
+ }
125
137
  targetView.addGestureRecognizer(recognizer)
126
138
  self.shakeMenuPinchGestureRecognizer = recognizer
127
139
  self.logger.info("Three finger pinch menu gesture initialized")
@@ -138,11 +150,7 @@ extension CapacitorUpdaterPlugin: UIGestureRecognizerDelegate {
138
150
  }
139
151
 
140
152
  @objc func handleShakeMenuPinch(_ recognizer: ThreeFingerPinchGestureRecognizer) {
141
- if recognizer.state == .ended || recognizer.state == .cancelled || recognizer.state == .failed {
142
- self.shakeMenuPinchGestureTriggered = false
143
- return
144
- }
145
- guard recognizer.state == .changed, !self.shakeMenuPinchGestureTriggered else {
153
+ guard recognizer.state == .recognized, !self.shakeMenuPinchGestureTriggered else {
146
154
  return
147
155
  }
148
156
  guard abs(recognizer.scale - 1) >= threeFingerPinchScaleDelta else {
@@ -156,6 +164,7 @@ extension CapacitorUpdaterPlugin: UIGestureRecognizerDelegate {
156
164
  }
157
165
 
158
166
  self.shakeMenuPinchGestureTriggered = true
167
+ self.logger.info("Three finger pinch detected")
159
168
  _ = window.showCapacitorUpdaterMenu(plugin: self, bridge: bridge, gestureName: "Three finger pinch")
160
169
  }
161
170
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/capacitor-updater",
3
- "version": "8.49.0",
3
+ "version": "8.49.1",
4
4
  "license": "MPL-2.0",
5
5
  "description": "Live update for capacitor apps",
6
6
  "main": "dist/plugin.cjs.js",