@capgo/capacitor-android-kiosk 7.0.0

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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Martin Donadieu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,340 @@
1
+ # @capgo/capacitor-android-kiosk
2
+
3
+ Android Kiosk Mode plugin for Capacitor - Lock device into kiosk mode with launcher functionality
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @capgo/capacitor-android-kiosk
9
+ npx cap sync
10
+ ```
11
+
12
+ ## Platform Support
13
+
14
+ This plugin is **Android-only**. For iOS kiosk mode functionality, please use the device's built-in [Guided Access](https://support.apple.com/en-us/HT202612) feature.
15
+
16
+ ## Features
17
+
18
+ - **Kiosk Mode**: Hide system UI and enter immersive fullscreen mode
19
+ - **Launcher Integration**: Set your app as the device launcher/home app
20
+ - **Hardware Key Control**: Block or allow specific hardware buttons
21
+ - **Status Detection**: Check if kiosk mode is active or if app is set as launcher
22
+ - **Android 6.0+**: Supports Android API 23 through Android 15 (API 35)
23
+
24
+ ## Usage
25
+
26
+ ### Basic Kiosk Mode
27
+
28
+ ```typescript
29
+ import { CapacitorAndroidKiosk } from '@capgo/capacitor-android-kiosk';
30
+
31
+ // Enter kiosk mode
32
+ await CapacitorAndroidKiosk.enterKioskMode();
33
+
34
+ // Exit kiosk mode
35
+ await CapacitorAndroidKiosk.exitKioskMode();
36
+
37
+ // Check if in kiosk mode
38
+ const { isInKioskMode } = await CapacitorAndroidKiosk.isInKioskMode();
39
+ console.log('Kiosk mode active:', isInKioskMode);
40
+ ```
41
+
42
+ ### Launcher Functionality
43
+
44
+ For full kiosk mode functionality, you need to set your app as the device launcher:
45
+
46
+ ```typescript
47
+ // Open home screen settings for user to select your app as launcher
48
+ await CapacitorAndroidKiosk.setAsLauncher();
49
+
50
+ // Check if app is set as launcher
51
+ const { isLauncher } = await CapacitorAndroidKiosk.isSetAsLauncher();
52
+ console.log('App is launcher:', isLauncher);
53
+ ```
54
+
55
+ ### Hardware Key Control
56
+
57
+ ```typescript
58
+ // Allow only volume keys
59
+ await CapacitorAndroidKiosk.setAllowedKeys({
60
+ volumeUp: true,
61
+ volumeDown: true,
62
+ back: false,
63
+ home: false,
64
+ recent: false
65
+ });
66
+
67
+ // Block all keys (default)
68
+ await CapacitorAndroidKiosk.setAllowedKeys({});
69
+ ```
70
+
71
+ ### Complete Example
72
+
73
+ ```typescript
74
+ async function setupKioskMode() {
75
+ try {
76
+ // Check if already set as launcher
77
+ const { isLauncher } = await CapacitorAndroidKiosk.isSetAsLauncher();
78
+
79
+ if (!isLauncher) {
80
+ // Prompt user to set as launcher
81
+ await CapacitorAndroidKiosk.setAsLauncher();
82
+ alert('Please select this app as your Home app');
83
+ return;
84
+ }
85
+
86
+ // Configure allowed keys
87
+ await CapacitorAndroidKiosk.setAllowedKeys({
88
+ volumeUp: true,
89
+ volumeDown: true,
90
+ back: false,
91
+ home: false,
92
+ recent: false,
93
+ power: false
94
+ });
95
+
96
+ // Enter kiosk mode
97
+ await CapacitorAndroidKiosk.enterKioskMode();
98
+ console.log('Kiosk mode activated');
99
+
100
+ } catch (error) {
101
+ console.error('Failed to setup kiosk mode:', error);
102
+ }
103
+ }
104
+ ```
105
+
106
+ ## API
107
+
108
+ <docgen-index>
109
+
110
+ * [`isInKioskMode()`](#isinkioskmode)
111
+ * [`isSetAsLauncher()`](#issetaslauncher)
112
+ * [`enterKioskMode()`](#enterkioskmode)
113
+ * [`exitKioskMode()`](#exitkioskmode)
114
+ * [`setAsLauncher()`](#setaslauncher)
115
+ * [`setAllowedKeys(...)`](#setallowedkeys)
116
+ * [`getPluginVersion()`](#getpluginversion)
117
+ * [Interfaces](#interfaces)
118
+
119
+ </docgen-index>
120
+
121
+ <docgen-api>
122
+ <!--Update the source file JSDoc comments and rerun docgen to update the docs below-->
123
+
124
+ Capacitor Android Kiosk Plugin for controlling kiosk mode and launcher functionality.
125
+ This plugin is Android-only. For iOS kiosk mode, use the device's Guided Access feature.
126
+
127
+ ### isInKioskMode()
128
+
129
+ ```typescript
130
+ isInKioskMode() => Promise<{ isInKioskMode: boolean; }>
131
+ ```
132
+
133
+ Checks if the app is currently running in kiosk mode.
134
+
135
+ **Returns:** <code>Promise&lt;{ isInKioskMode: boolean; }&gt;</code>
136
+
137
+ **Since:** 1.0.0
138
+
139
+ --------------------
140
+
141
+
142
+ ### isSetAsLauncher()
143
+
144
+ ```typescript
145
+ isSetAsLauncher() => Promise<{ isLauncher: boolean; }>
146
+ ```
147
+
148
+ Checks if the app is set as the device launcher (home app).
149
+
150
+ **Returns:** <code>Promise&lt;{ isLauncher: boolean; }&gt;</code>
151
+
152
+ **Since:** 1.0.0
153
+
154
+ --------------------
155
+
156
+
157
+ ### enterKioskMode()
158
+
159
+ ```typescript
160
+ enterKioskMode() => Promise<void>
161
+ ```
162
+
163
+ Enters kiosk mode, hiding system UI and blocking hardware buttons.
164
+ The app must be set as the device launcher for this to work effectively.
165
+
166
+ **Since:** 1.0.0
167
+
168
+ --------------------
169
+
170
+
171
+ ### exitKioskMode()
172
+
173
+ ```typescript
174
+ exitKioskMode() => Promise<void>
175
+ ```
176
+
177
+ Exits kiosk mode, restoring normal system UI and hardware button functionality.
178
+
179
+ **Since:** 1.0.0
180
+
181
+ --------------------
182
+
183
+
184
+ ### setAsLauncher()
185
+
186
+ ```typescript
187
+ setAsLauncher() => Promise<void>
188
+ ```
189
+
190
+ Opens the device's home screen settings to allow user to set this app as the launcher.
191
+ This is required for full kiosk mode functionality.
192
+
193
+ **Since:** 1.0.0
194
+
195
+ --------------------
196
+
197
+
198
+ ### setAllowedKeys(...)
199
+
200
+ ```typescript
201
+ setAllowedKeys(options: AllowedKeysOptions) => Promise<void>
202
+ ```
203
+
204
+ Sets which hardware keys are allowed to function in kiosk mode.
205
+ By default, all hardware keys are blocked in kiosk mode.
206
+
207
+ | Param | Type | Description |
208
+ | ------------- | ----------------------------------------------------------------- | ------------------------------ |
209
+ | **`options`** | <code><a href="#allowedkeysoptions">AllowedKeysOptions</a></code> | Configuration for allowed keys |
210
+
211
+ **Since:** 1.0.0
212
+
213
+ --------------------
214
+
215
+
216
+ ### getPluginVersion()
217
+
218
+ ```typescript
219
+ getPluginVersion() => Promise<{ version: string; }>
220
+ ```
221
+
222
+ Get the native Capacitor plugin version.
223
+
224
+ **Returns:** <code>Promise&lt;{ version: string; }&gt;</code>
225
+
226
+ **Since:** 1.0.0
227
+
228
+ --------------------
229
+
230
+
231
+ ### Interfaces
232
+
233
+
234
+ #### AllowedKeysOptions
235
+
236
+ Configuration options for allowed hardware keys in kiosk mode.
237
+
238
+ | Prop | Type | Description | Default |
239
+ | ---------------- | -------------------- | -------------------------------- | ------------------ |
240
+ | **`volumeUp`** | <code>boolean</code> | Allow volume up button | <code>false</code> |
241
+ | **`volumeDown`** | <code>boolean</code> | Allow volume down button | <code>false</code> |
242
+ | **`back`** | <code>boolean</code> | Allow back button | <code>false</code> |
243
+ | **`home`** | <code>boolean</code> | Allow home button | <code>false</code> |
244
+ | **`recent`** | <code>boolean</code> | Allow recent apps button | <code>false</code> |
245
+ | **`power`** | <code>boolean</code> | Allow power button | <code>false</code> |
246
+ | **`camera`** | <code>boolean</code> | Allow camera button (if present) | <code>false</code> |
247
+ | **`menu`** | <code>boolean</code> | Allow menu button (if present) | <code>false</code> |
248
+
249
+ </docgen-api>
250
+
251
+ ## Android Configuration
252
+
253
+ ### 1. MainActivity Setup
254
+
255
+ To enable full hardware key blocking, you need to override `dispatchKeyEvent` in your `MainActivity.java`:
256
+
257
+ ```java
258
+ import android.view.KeyEvent;
259
+ import ee.forgr.plugin.android_kiosk.CapacitorAndroidKioskPlugin;
260
+
261
+ public class MainActivity extends BridgeActivity {
262
+ @Override
263
+ public boolean dispatchKeyEvent(KeyEvent event) {
264
+ // Get the kiosk plugin
265
+ CapacitorAndroidKioskPlugin kioskPlugin = (CapacitorAndroidKioskPlugin)
266
+ this.getBridge().getPlugin("CapacitorAndroidKiosk").getInstance();
267
+
268
+ if (kioskPlugin != null && kioskPlugin.shouldBlockKey(event.getKeyCode())) {
269
+ return true; // Block the key
270
+ }
271
+
272
+ return super.dispatchKeyEvent(event);
273
+ }
274
+
275
+ @Override
276
+ public void onBackPressed() {
277
+ // Don't call super.onBackPressed() to disable back button
278
+ // Or call the plugin's handleOnBackPressed
279
+ }
280
+ }
281
+ ```
282
+
283
+ ### 2. AndroidManifest.xml
284
+
285
+ Add launcher intent filter to make your app selectable as a launcher:
286
+
287
+ ```xml
288
+ <activity
289
+ android:name=".MainActivity"
290
+ ...>
291
+
292
+ <!-- Existing intent filter -->
293
+ <intent-filter>
294
+ <action android:name="android.intent.action.MAIN" />
295
+ <category android:name="android.intent.category.LAUNCHER" />
296
+ </intent-filter>
297
+
298
+ <!-- Add this to make app selectable as launcher -->
299
+ <intent-filter>
300
+ <action android:name="android.intent.action.MAIN" />
301
+ <category android:name="android.intent.category.HOME" />
302
+ <category android:name="android.intent.category.DEFAULT" />
303
+ </intent-filter>
304
+ </activity>
305
+ ```
306
+
307
+ ## Important Notes
308
+
309
+ 1. **Launcher Requirement**: For full kiosk mode functionality (blocking home button, preventing task switching), your app must be set as the device launcher.
310
+
311
+ 2. **Testing**: When testing, you can exit kiosk mode programmatically or by setting another app as the launcher.
312
+
313
+ 3. **Android Versions**: The plugin uses modern Android APIs for Android 11+ and falls back to older methods for compatibility with Android 6.0+.
314
+
315
+ 4. **Security**: This plugin is designed for legitimate kiosk applications. Ensure you provide users with a way to exit kiosk mode.
316
+
317
+ 5. **Battery**: Kiosk mode keeps the screen on. Consider implementing your own screen timeout or brightness management.
318
+
319
+ ## iOS Alternative
320
+
321
+ For iOS devices, use the built-in [Guided Access](https://support.apple.com/en-us/HT202612) feature:
322
+
323
+ 1. Go to Settings > Accessibility > Guided Access
324
+ 2. Turn on Guided Access
325
+ 3. Set a passcode
326
+ 4. Open your app
327
+ 5. Triple-click the side button
328
+ 6. Adjust settings and start Guided Access
329
+
330
+ ## Contributing
331
+
332
+ See [CONTRIBUTING.md](CONTRIBUTING.md)
333
+
334
+ ## License
335
+
336
+ MIT
337
+
338
+ ## Author
339
+
340
+ Martin Donadieu <martin@capgo.app>
@@ -0,0 +1,59 @@
1
+ ext {
2
+ junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
3
+ androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.2.1'
4
+ androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.6.1'
5
+ androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.0'
6
+ }
7
+
8
+ buildscript {
9
+ repositories {
10
+ mavenCentral()
11
+ google()
12
+ }
13
+ dependencies {
14
+ classpath 'com.android.tools.build:gradle:8.7.2'
15
+ }
16
+ }
17
+
18
+ apply plugin: 'com.android.library'
19
+
20
+ android {
21
+ namespace "ee.forgr.plugin.android_kiosk"
22
+ compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 35
23
+ defaultConfig {
24
+ minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 23
25
+ targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 35
26
+ versionCode 1
27
+ versionName "1.0"
28
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
29
+ }
30
+ buildTypes {
31
+ release {
32
+ minifyEnabled false
33
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
34
+ }
35
+ }
36
+ lintOptions {
37
+ abortOnError false
38
+ }
39
+ compileOptions {
40
+ sourceCompatibility JavaVersion.VERSION_21
41
+ targetCompatibility JavaVersion.VERSION_21
42
+ }
43
+ }
44
+
45
+ repositories {
46
+ google()
47
+ jcenter()
48
+ mavenCentral()
49
+ }
50
+
51
+
52
+ dependencies {
53
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
54
+ implementation project(':capacitor-android')
55
+ implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
56
+ testImplementation "junit:junit:$junitVersion"
57
+ androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
58
+ androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
59
+ }
@@ -0,0 +1,2 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ </manifest>
@@ -0,0 +1,283 @@
1
+ package ee.forgr.plugin.android_kiosk;
2
+
3
+ import android.app.Activity;
4
+ import android.app.ActivityManager;
5
+ import android.content.ComponentName;
6
+ import android.content.Context;
7
+ import android.content.Intent;
8
+ import android.content.pm.PackageManager;
9
+ import android.os.Build;
10
+ import android.view.KeyEvent;
11
+ import android.view.View;
12
+ import android.view.WindowManager;
13
+ import com.getcapacitor.JSObject;
14
+ import com.getcapacitor.Plugin;
15
+ import com.getcapacitor.PluginCall;
16
+ import com.getcapacitor.PluginMethod;
17
+ import com.getcapacitor.annotation.CapacitorPlugin;
18
+ import java.util.HashSet;
19
+ import java.util.Set;
20
+
21
+ @CapacitorPlugin(name = "CapacitorAndroidKiosk")
22
+ public class CapacitorAndroidKioskPlugin extends Plugin {
23
+
24
+ private final String pluginVersion = "1.0.0";
25
+ private boolean isInKioskMode = false;
26
+ private final Set<Integer> allowedKeys = new HashSet<>();
27
+
28
+ @Override
29
+ public void load() {
30
+ // Initialize with no allowed keys by default
31
+ allowedKeys.clear();
32
+ }
33
+
34
+ @PluginMethod
35
+ public void isInKioskMode(PluginCall call) {
36
+ JSObject ret = new JSObject();
37
+ ret.put("isInKioskMode", isInKioskMode);
38
+ call.resolve(ret);
39
+ }
40
+
41
+ @PluginMethod
42
+ public void isSetAsLauncher(PluginCall call) {
43
+ JSObject ret = new JSObject();
44
+ boolean isLauncher = checkIfLauncher();
45
+ ret.put("isLauncher", isLauncher);
46
+ call.resolve(ret);
47
+ }
48
+
49
+ @PluginMethod
50
+ public void enterKioskMode(PluginCall call) {
51
+ try {
52
+ Activity activity = getActivity();
53
+ if (activity == null) {
54
+ call.reject("Activity not available");
55
+ return;
56
+ }
57
+
58
+ activity.runOnUiThread(() -> {
59
+ try {
60
+ View decorView = activity.getWindow().getDecorView();
61
+
62
+ // Hide system UI for different Android versions
63
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
64
+ // Android 11+ (API 30+)
65
+ activity.getWindow().setDecorFitsSystemWindows(false);
66
+ android.view.WindowInsetsController controller = decorView.getWindowInsetsController();
67
+ if (controller != null) {
68
+ controller.hide(android.view.WindowInsets.Type.statusBars() | android.view.WindowInsets.Type.navigationBars());
69
+ controller.setSystemBarsBehavior(android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE);
70
+ }
71
+ } else {
72
+ // Android 10 and below
73
+ int uiOptions =
74
+ View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
75
+ View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
76
+ View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
77
+ View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
78
+ View.SYSTEM_UI_FLAG_FULLSCREEN |
79
+ View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
80
+ decorView.setSystemUiVisibility(uiOptions);
81
+ }
82
+
83
+ // Keep screen on
84
+ activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
85
+
86
+ // Prevent status bar from being pulled down
87
+ activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
88
+
89
+ isInKioskMode = true;
90
+ call.resolve();
91
+ } catch (Exception e) {
92
+ call.reject("Failed to enter kiosk mode", e);
93
+ }
94
+ });
95
+ } catch (Exception e) {
96
+ call.reject("Failed to enter kiosk mode", e);
97
+ }
98
+ }
99
+
100
+ @PluginMethod
101
+ public void exitKioskMode(PluginCall call) {
102
+ try {
103
+ Activity activity = getActivity();
104
+ if (activity == null) {
105
+ call.reject("Activity not available");
106
+ return;
107
+ }
108
+
109
+ activity.runOnUiThread(() -> {
110
+ try {
111
+ View decorView = activity.getWindow().getDecorView();
112
+
113
+ // Restore system UI for different Android versions
114
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
115
+ // Android 11+ (API 30+)
116
+ activity.getWindow().setDecorFitsSystemWindows(true);
117
+ android.view.WindowInsetsController controller = decorView.getWindowInsetsController();
118
+ if (controller != null) {
119
+ controller.show(android.view.WindowInsets.Type.statusBars() | android.view.WindowInsets.Type.navigationBars());
120
+ }
121
+ } else {
122
+ // Android 10 and below
123
+ decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
124
+ }
125
+
126
+ // Clear screen on flag
127
+ activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
128
+
129
+ // Clear fullscreen flag
130
+ activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
131
+
132
+ isInKioskMode = false;
133
+ call.resolve();
134
+ } catch (Exception e) {
135
+ call.reject("Failed to exit kiosk mode", e);
136
+ }
137
+ });
138
+ } catch (Exception e) {
139
+ call.reject("Failed to exit kiosk mode", e);
140
+ }
141
+ }
142
+
143
+ @PluginMethod
144
+ public void setAsLauncher(PluginCall call) {
145
+ try {
146
+ Context context = getContext();
147
+ if (context == null) {
148
+ call.reject("Context not available");
149
+ return;
150
+ }
151
+
152
+ // Enable launcher intent filter
153
+ ComponentName componentName = new ComponentName(context, getLauncherActivity());
154
+ PackageManager packageManager = context.getPackageManager();
155
+ packageManager.setComponentEnabledSetting(
156
+ componentName,
157
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
158
+ PackageManager.DONT_KILL_APP
159
+ );
160
+
161
+ // Open home screen settings
162
+ Intent intent = new Intent(android.provider.Settings.ACTION_HOME_SETTINGS);
163
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
164
+ context.startActivity(intent);
165
+
166
+ call.resolve();
167
+ } catch (Exception e) {
168
+ call.reject("Failed to set as launcher", e);
169
+ }
170
+ }
171
+
172
+ @PluginMethod
173
+ public void setAllowedKeys(PluginCall call) {
174
+ allowedKeys.clear();
175
+
176
+ // Parse allowed keys from options
177
+ if (call.getBoolean("volumeUp", false)) {
178
+ allowedKeys.add(KeyEvent.KEYCODE_VOLUME_UP);
179
+ }
180
+ if (call.getBoolean("volumeDown", false)) {
181
+ allowedKeys.add(KeyEvent.KEYCODE_VOLUME_DOWN);
182
+ }
183
+ if (call.getBoolean("back", false)) {
184
+ allowedKeys.add(KeyEvent.KEYCODE_BACK);
185
+ }
186
+ if (call.getBoolean("home", false)) {
187
+ allowedKeys.add(KeyEvent.KEYCODE_HOME);
188
+ }
189
+ if (call.getBoolean("recent", false)) {
190
+ allowedKeys.add(KeyEvent.KEYCODE_APP_SWITCH);
191
+ }
192
+ if (call.getBoolean("power", false)) {
193
+ allowedKeys.add(KeyEvent.KEYCODE_POWER);
194
+ }
195
+ if (call.getBoolean("camera", false)) {
196
+ allowedKeys.add(KeyEvent.KEYCODE_CAMERA);
197
+ }
198
+ if (call.getBoolean("menu", false)) {
199
+ allowedKeys.add(KeyEvent.KEYCODE_MENU);
200
+ }
201
+
202
+ call.resolve();
203
+ }
204
+
205
+ @PluginMethod
206
+ public void getPluginVersion(PluginCall call) {
207
+ try {
208
+ JSObject ret = new JSObject();
209
+ ret.put("version", pluginVersion);
210
+ call.resolve(ret);
211
+ } catch (Exception e) {
212
+ call.reject("Could not get plugin version", e);
213
+ }
214
+ }
215
+
216
+ /**
217
+ * Handle key events to block hardware buttons when in kiosk mode
218
+ * This method should be called from the main activity's dispatchKeyEvent
219
+ */
220
+ @Override
221
+ protected void handleOnPause() {
222
+ super.handleOnPause();
223
+ if (isInKioskMode) {
224
+ Activity activity = getActivity();
225
+ if (activity != null) {
226
+ // Bring app back to foreground if in kiosk mode
227
+ ActivityManager activityManager = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);
228
+ if (activityManager != null) {
229
+ activityManager.moveTaskToFront(activity.getTaskId(), 0);
230
+ }
231
+ }
232
+ }
233
+ }
234
+
235
+ /**
236
+ * Check if this app is set as the default launcher
237
+ */
238
+ private boolean checkIfLauncher() {
239
+ try {
240
+ Context context = getContext();
241
+ if (context == null) {
242
+ return false;
243
+ }
244
+
245
+ Intent intent = new Intent(Intent.ACTION_MAIN);
246
+ intent.addCategory(Intent.CATEGORY_HOME);
247
+
248
+ PackageManager packageManager = context.getPackageManager();
249
+ ComponentName componentName = intent.resolveActivity(packageManager);
250
+
251
+ if (componentName == null) {
252
+ return false;
253
+ }
254
+
255
+ return componentName.getPackageName().equals(context.getPackageName());
256
+ } catch (Exception e) {
257
+ return false;
258
+ }
259
+ }
260
+
261
+ /**
262
+ * Get the launcher activity class
263
+ * This should be the main activity of the Capacitor app
264
+ */
265
+ private Class<?> getLauncherActivity() {
266
+ Activity activity = getActivity();
267
+ if (activity != null) {
268
+ return activity.getClass();
269
+ }
270
+ return null;
271
+ }
272
+
273
+ /**
274
+ * Check if a key event should be blocked
275
+ * Call this from your MainActivity's dispatchKeyEvent method
276
+ */
277
+ public boolean shouldBlockKey(int keyCode) {
278
+ if (!isInKioskMode) {
279
+ return false;
280
+ }
281
+ return !allowedKeys.contains(keyCode);
282
+ }
283
+ }
File without changes