frida-float-menu 1.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/README.md +404 -0
- package/lib/api.d.ts +50 -0
- package/lib/api.js +149 -0
- package/lib/component/button.d.ts +11 -0
- package/lib/component/button.js +57 -0
- package/lib/component/category.d.ts +8 -0
- package/lib/component/category.js +37 -0
- package/lib/component/checkBox.d.ts +28 -0
- package/lib/component/checkBox.js +199 -0
- package/lib/component/collapsible.d.ts +19 -0
- package/lib/component/collapsible.js +177 -0
- package/lib/component/image.d.ts +18 -0
- package/lib/component/image.js +87 -0
- package/lib/component/input.d.ts +33 -0
- package/lib/component/input.js +346 -0
- package/lib/component/selector.d.ts +22 -0
- package/lib/component/selector.js +95 -0
- package/lib/component/slider.d.ts +18 -0
- package/lib/component/slider.js +155 -0
- package/lib/component/style/style.d.ts +5 -0
- package/lib/component/style/style.js +261 -0
- package/lib/component/style/theme.d.ts +29 -0
- package/lib/component/style/theme.js +23 -0
- package/lib/component/switch.d.ts +12 -0
- package/lib/component/switch.js +77 -0
- package/lib/component/text.d.ts +9 -0
- package/lib/component/text.js +36 -0
- package/lib/component/ui-components.d.ts +24 -0
- package/lib/component/ui-components.js +49 -0
- package/lib/component/views/log-view.d.ts +25 -0
- package/lib/component/views/log-view.js +231 -0
- package/lib/component/views/tabs-view.d.ts +35 -0
- package/lib/component/views/tabs-view.js +296 -0
- package/lib/event-emitter.d.ts +10 -0
- package/lib/event-emitter.js +52 -0
- package/lib/float-menu.d.ts +63 -0
- package/lib/float-menu.js +568 -0
- package/lib/index.d.ts +12 -0
- package/lib/index.js +28 -0
- package/lib/logger.d.ts +43 -0
- package/lib/logger.js +183 -0
- package/lib/utils.d.ts +8 -0
- package/lib/utils.js +16 -0
- package/package.json +36 -0
package/README.md
ADDED
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
# Frida Floating Menu UI Library
|
|
2
|
+
|
|
3
|
+
A TypeScript library for creating interactive floating windows on Android devices with UI components (buttons, switches, text, selectors) that can be controlled from JavaScript. Designed for Frida instrumentation and reverse engineering.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Create floating overlay windows using Android's `WindowManager`
|
|
8
|
+
- Add interactive UI components: Button, Switch, Text label, Selector (dropdown), Slider, Collapsible panel, Category header, TextInput, NumberInput
|
|
9
|
+
- Two-way data binding: JavaScript variables ↔ UI state synchronization
|
|
10
|
+
- Event system for UI interactions (clicks, value changes)
|
|
11
|
+
- Update UI components programmatically from JavaScript
|
|
12
|
+
- Optional log panel to display runtime logs (can be disabled for performance)
|
|
13
|
+
- Set window icon via base64-encoded image
|
|
14
|
+
- Modular, extensible architecture
|
|
15
|
+
- TypeScript support with full type definitions
|
|
16
|
+
|
|
17
|
+
## Requirements
|
|
18
|
+
|
|
19
|
+
- Frida (tested on Android)
|
|
20
|
+
- Target Android app with overlay permission (`TYPE_APPLICATION_OVERLAY`, API 26+)
|
|
21
|
+
- Frida-compile for TypeScript compilation (included as dev dependency)
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
### As a library in your Frida project
|
|
26
|
+
|
|
27
|
+
1. Copy the `src/` directory to your project
|
|
28
|
+
2. Import the library in your TypeScript files:
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
import { FloatMenu, Button, Switch } from './path/to/src/index';
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### As a standalone package (conceptual)
|
|
35
|
+
|
|
36
|
+
Since this is a library, you typically include the source code in your project rather than installing from npm.
|
|
37
|
+
|
|
38
|
+
## Quick Start
|
|
39
|
+
|
|
40
|
+
### 1. Create a TypeScript file (`my-script.ts`)
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
import { FloatMenu, Button, Switch, Text, Selector } from './src/index';
|
|
44
|
+
|
|
45
|
+
Java.perform(() => {
|
|
46
|
+
// Create floating menu
|
|
47
|
+
const menu = new FloatMenu({
|
|
48
|
+
width: 300,
|
|
49
|
+
height: 400,
|
|
50
|
+
x: 100,
|
|
51
|
+
y: 100,
|
|
52
|
+
showLogs: true
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
menu.show();
|
|
56
|
+
|
|
57
|
+
// Add components
|
|
58
|
+
const button = new Button('myButton', 'Click Me');
|
|
59
|
+
button.setOnClick(() => {
|
|
60
|
+
console.log('Button clicked!');
|
|
61
|
+
});
|
|
62
|
+
menu.addComponent('myButton', button);
|
|
63
|
+
|
|
64
|
+
const switchComp = new Switch('mySwitch', 'Enable Feature', false);
|
|
65
|
+
switchComp.on('valueChanged', (value: boolean) => {
|
|
66
|
+
console.log('Switch:', value);
|
|
67
|
+
});
|
|
68
|
+
menu.addComponent('mySwitch', switchComp);
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### 2. Compile with frida-compile
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
frida-compile my-script.ts -o my-script.js -c
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 3. Inject into target
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
frida -U -f com.example.app -l my-script.js
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## API Reference
|
|
85
|
+
|
|
86
|
+
### FloatMenu
|
|
87
|
+
|
|
88
|
+
Main class for creating and managing floating windows.
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
interface TabDefinition {
|
|
92
|
+
id: string; // Unique tab identifier
|
|
93
|
+
label: string; // Display label for tab button
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
interface FloatMenuOptions {
|
|
97
|
+
width?: number; // Window width (default: 1000)
|
|
98
|
+
height?: number; // Window height (default: 900)
|
|
99
|
+
x?: number; // X position (default: 100)
|
|
100
|
+
y?: number; // Y position (default: 100)
|
|
101
|
+
iconVisible?: boolean; // Show icon initially (default: true)
|
|
102
|
+
iconWidth?: number; // Icon width (default: 200)
|
|
103
|
+
iconHeight?: number; // Icon height (default: 200)
|
|
104
|
+
iconBase64?: string; // Base64-encoded icon image (optional)
|
|
105
|
+
showLogs?: boolean; // Show log panel (default: false)
|
|
106
|
+
logMaxLines?: number; // Max lines in log panel (default: 100)
|
|
107
|
+
title?: string; // Main title text (default: "Frida Float Menu")
|
|
108
|
+
subtitle?: string; // Subtitle text (default: "Interactive Debugging Panel")
|
|
109
|
+
showHeader?: boolean; // Whether to show header (default: true)
|
|
110
|
+
showFooter?: boolean; // Whether to show footer (default: true)
|
|
111
|
+
tabs?: TabDefinition[]; // Tab definitions (optional)
|
|
112
|
+
activeTab?: string; // Initially active tab ID (default: first tab or "default")
|
|
113
|
+
showTabs?: boolean; // Whether to show tab bar (default: true if tabs are defined)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
class FloatMenu {
|
|
117
|
+
constructor(options?: FloatMenuOptions);
|
|
118
|
+
show(): void; // Display window
|
|
119
|
+
hide(): void; // Hide and destroy window
|
|
120
|
+
addComponent(id: string, component: UIComponent, tabId?: string): void;
|
|
121
|
+
removeComponent(id: string): void;
|
|
122
|
+
getComponent<T extends UIComponent>(id: string): T | undefined;
|
|
123
|
+
setComponentValue(id: string, value: any): void;
|
|
124
|
+
switchTab(tabId: string): void; // Switch to a different tab
|
|
125
|
+
getActiveTabId(): string; // Get currently active tab ID
|
|
126
|
+
on(event: string, callback: (...args: any[]) => void): void;
|
|
127
|
+
off(event: string, callback: (...args: any[]) => void): void;
|
|
128
|
+
setPosition(x: number, y: number): void;
|
|
129
|
+
setSize(width: number, height: number): void;
|
|
130
|
+
clearLogs(): void;
|
|
131
|
+
showIcon(): void; // Minimize to icon
|
|
132
|
+
showMenu(): void; // Expand to menu
|
|
133
|
+
toggleView(): void; // Toggle between icon and menu
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### UI Components
|
|
138
|
+
|
|
139
|
+
All components extend `UIComponent` base class.
|
|
140
|
+
|
|
141
|
+
#### Button
|
|
142
|
+
```typescript
|
|
143
|
+
class Button extends UIComponent {
|
|
144
|
+
constructor(id: string, label: string);
|
|
145
|
+
setOnClick(handler: () => void): void;
|
|
146
|
+
setLabel(label: string): void;
|
|
147
|
+
// Emits 'click' event
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
#### Switch
|
|
152
|
+
```typescript
|
|
153
|
+
class Switch extends UIComponent {
|
|
154
|
+
constructor(id: string, label: string, initialValue?: boolean);
|
|
155
|
+
setLabel(label: string): void;
|
|
156
|
+
// Emits 'valueChanged' event with boolean value
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
#### Text
|
|
161
|
+
```typescript
|
|
162
|
+
class Text extends UIComponent {
|
|
163
|
+
constructor(id: string, content: string);
|
|
164
|
+
setText(content: string): void;
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
#### Selector (Dropdown)
|
|
169
|
+
```typescript
|
|
170
|
+
class Selector extends UIComponent {
|
|
171
|
+
constructor(id: string, items: string[], selectedIndex?: number);
|
|
172
|
+
setItems(items: string[]): void;
|
|
173
|
+
getSelectedIndex(): number;
|
|
174
|
+
// Emits 'valueChanged' event with selected string
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
#### Slider (SeekBar)
|
|
179
|
+
```typescript
|
|
180
|
+
class Slider extends UIComponent {
|
|
181
|
+
constructor(id: string, label: string, min: number, max: number, initialValue?: number, step?: number);
|
|
182
|
+
setLabel(label: string): void;
|
|
183
|
+
setRange(min: number, max: number, step?: number): void;
|
|
184
|
+
// Emits 'valueChanged' event with numeric value
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
#### Collapsible (Expandable Panel)
|
|
189
|
+
```typescript
|
|
190
|
+
class Collapsible extends UIComponent {
|
|
191
|
+
constructor(id: string, title: string, expanded?: boolean);
|
|
192
|
+
setTitle(title: string): void;
|
|
193
|
+
toggle(): void; // Toggle expanded/collapsed state
|
|
194
|
+
expand(): void; // Expand panel
|
|
195
|
+
collapse(): void; // Collapse panel
|
|
196
|
+
addChildView(view: any): void; // Add child component view
|
|
197
|
+
removeChildView(view: any): void; // Remove child component view
|
|
198
|
+
clearChildren(): void; // Remove all child views
|
|
199
|
+
// Emits 'toggle', 'expand', 'collapse' events
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
#### Category (Section Header)
|
|
204
|
+
```typescript
|
|
205
|
+
class Category extends UIComponent {
|
|
206
|
+
constructor(id: string, label: string);
|
|
207
|
+
setLabel(label: string): void;
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
#### TextInput (EditText)
|
|
212
|
+
```typescript
|
|
213
|
+
class TextInput extends UIComponent {
|
|
214
|
+
constructor(id: string, initialValue?: string, hint?: string, multiline?: boolean);
|
|
215
|
+
setHint(hint: string): void;
|
|
216
|
+
setMultiline(multiline: boolean): void;
|
|
217
|
+
getText(): string;
|
|
218
|
+
setText(text: string): void;
|
|
219
|
+
// Emits 'valueChanged' event with string value
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
#### NumberInput (Numeric EditText)
|
|
224
|
+
```typescript
|
|
225
|
+
class NumberInput extends UIComponent {
|
|
226
|
+
constructor(id: string, initialValue?: number, hint?: string, min?: number, max?: number, step?: number);
|
|
227
|
+
setHint(hint: string): void;
|
|
228
|
+
setConstraints(min: number | null, max: number | null, step: number | null): void;
|
|
229
|
+
getNumber(): number;
|
|
230
|
+
setNumber(value: number): void;
|
|
231
|
+
// Emits 'valueChanged' event with numeric value
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Event System
|
|
236
|
+
|
|
237
|
+
Components emit events that can be listened to:
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
// Component-level events
|
|
241
|
+
component.on('valueChanged', (value) => { /* Switch or Selector value changed */ });
|
|
242
|
+
component.on('click', () => { /* Button clicked */ });
|
|
243
|
+
|
|
244
|
+
// Menu forwards component events with IDs
|
|
245
|
+
menu.on('component:mySwitch:valueChanged', (value) => {
|
|
246
|
+
console.log('Switch with ID "mySwitch" changed to:', value);
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
// Tab change events
|
|
250
|
+
menu.on('tabChanged', (newTabId: string, oldTabId: string) => {
|
|
251
|
+
console.log(`Tab changed from ${oldTabId} to ${newTabId}`);
|
|
252
|
+
});
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Logger
|
|
256
|
+
|
|
257
|
+
Optional logging system with configurable levels:
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
import { Logger, LogLevel } from './src/index';
|
|
261
|
+
|
|
262
|
+
const logger = new Logger('debug'); // 'debug' | 'info' | 'warn' | 'error' | 'none'
|
|
263
|
+
logger.info('Message');
|
|
264
|
+
logger.debug('Debug info');
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## Examples
|
|
268
|
+
|
|
269
|
+
### Basic Example
|
|
270
|
+
|
|
271
|
+
See `example.ts` for a complete TypeScript example with all components.
|
|
272
|
+
|
|
273
|
+
### Tabbed Interface Example
|
|
274
|
+
|
|
275
|
+
Create a floating menu with multiple tabs:
|
|
276
|
+
|
|
277
|
+
```typescript
|
|
278
|
+
const menu = new FloatMenu({
|
|
279
|
+
width: 1000,
|
|
280
|
+
height: 900,
|
|
281
|
+
tabs: [
|
|
282
|
+
{ id: "controls", label: "Controls" },
|
|
283
|
+
{ id: "settings", label: "Settings" },
|
|
284
|
+
{ id: "info", label: "Info" }
|
|
285
|
+
],
|
|
286
|
+
activeTab: "controls",
|
|
287
|
+
showTabs: true,
|
|
288
|
+
title: "Multi-tab Menu",
|
|
289
|
+
subtitle: "Organize your UI in tabs"
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
menu.show();
|
|
293
|
+
|
|
294
|
+
// Add components to specific tabs
|
|
295
|
+
const button = new Button("btn1", "Click Me");
|
|
296
|
+
menu.addComponent("btn1", button, "controls");
|
|
297
|
+
|
|
298
|
+
const switchComp = new Switch("switch1", "Enable", false);
|
|
299
|
+
menu.addComponent("switch1", switchComp, "settings");
|
|
300
|
+
|
|
301
|
+
// Listen for tab changes
|
|
302
|
+
menu.on("tabChanged", (newTabId, oldTabId) => {
|
|
303
|
+
console.log(`Tab changed: ${oldTabId} -> ${newTabId}`);
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
// Switch tabs programmatically
|
|
307
|
+
menu.switchTab("settings");
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### Global Attachment (for simple scripts)
|
|
311
|
+
|
|
312
|
+
If you prefer global variables instead of imports:
|
|
313
|
+
|
|
314
|
+
```typescript
|
|
315
|
+
import { attachToGlobal } from './src/index';
|
|
316
|
+
attachToGlobal(globalThis);
|
|
317
|
+
|
|
318
|
+
// Now classes are available globally
|
|
319
|
+
Java.perform(() => {
|
|
320
|
+
const menu = new FloatMenu({ width: 300, height: 400 });
|
|
321
|
+
menu.show();
|
|
322
|
+
});
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### Dynamic UI Updates
|
|
326
|
+
|
|
327
|
+
```typescript
|
|
328
|
+
// Update UI from JavaScript
|
|
329
|
+
setTimeout(() => {
|
|
330
|
+
menu.setComponentValue('mySwitch', true); // Turn switch on
|
|
331
|
+
const textComp = menu.getComponent<Text>('myText');
|
|
332
|
+
if (textComp) {
|
|
333
|
+
textComp.setText('Updated!');
|
|
334
|
+
}
|
|
335
|
+
}, 5000);
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
### New Components Demo
|
|
339
|
+
|
|
340
|
+
A comprehensive demo showcasing all new UI components is available in `demo-new-components.ts`:
|
|
341
|
+
|
|
342
|
+
```bash
|
|
343
|
+
# Build the demo
|
|
344
|
+
npm run build:demo
|
|
345
|
+
|
|
346
|
+
# Run the demo with Frida
|
|
347
|
+
npm run frida:demo
|
|
348
|
+
|
|
349
|
+
# Or compile manually
|
|
350
|
+
frida-compile demo-new-components.ts -o demo-new-components-compiled.js -c
|
|
351
|
+
frida -U -f com.example.app -l demo-new-components-compiled.js
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
The demo demonstrates:
|
|
355
|
+
- **Slider**: Range control with min/max/step constraints
|
|
356
|
+
- **Collapsible**: Expandable/collapsible panels with child components
|
|
357
|
+
- **Category**: Section headers for organizing UI
|
|
358
|
+
- **TextInput**: Single and multi-line text entry
|
|
359
|
+
- **NumberInput**: Numeric input with validation and constraints
|
|
360
|
+
- **Interaction**: Components communicating with each other
|
|
361
|
+
|
|
362
|
+
## Project Structure
|
|
363
|
+
|
|
364
|
+
```
|
|
365
|
+
frida-float-menu/
|
|
366
|
+
├── src/ # Library source code
|
|
367
|
+
│ ├── index.ts # Main entry point (re-exports everything)
|
|
368
|
+
│ ├── event-emitter.ts # Event system
|
|
369
|
+
│ ├── logger.ts # Logging utilities
|
|
370
|
+
│ ├── ui-components.ts # UI component definitions (all components)
|
|
371
|
+
│ └── float-menu.ts # FloatMenu main class
|
|
372
|
+
├── example.ts # TypeScript usage example (basic components)
|
|
373
|
+
├── demo-new-components.ts # TypeScript demo for new components
|
|
374
|
+
├── example.js # JavaScript usage example
|
|
375
|
+
├── package.json # Package configuration
|
|
376
|
+
└── README.md # This file
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
## Building and Development
|
|
380
|
+
|
|
381
|
+
### For library users
|
|
382
|
+
No build required - use the TypeScript source directly with frida-compile.
|
|
383
|
+
|
|
384
|
+
### For library developers
|
|
385
|
+
```bash
|
|
386
|
+
npm install # Install dependencies
|
|
387
|
+
npm run check # Type-check without emitting
|
|
388
|
+
npm run build-example # Build example script
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
## Limitations
|
|
392
|
+
|
|
393
|
+
- Requires Android API level 26+ for `TYPE_APPLICATION_OVERLAY`
|
|
394
|
+
- UI operations automatically scheduled on main thread
|
|
395
|
+
- Uses default Android widgets (no custom styling)
|
|
396
|
+
- Tested on Android only (not iOS)
|
|
397
|
+
|
|
398
|
+
## License
|
|
399
|
+
|
|
400
|
+
MIT
|
|
401
|
+
|
|
402
|
+
## Contributing
|
|
403
|
+
|
|
404
|
+
Contributions are welcome! Please submit issues and pull requests to enhance the library.
|
package/lib/api.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export declare const API: {
|
|
2
|
+
readonly ImageView: Java.Wrapper<{}>;
|
|
3
|
+
readonly ImageViewScaleType: Java.Wrapper<{}>;
|
|
4
|
+
readonly FrameLayoutParams: Java.Wrapper<{}>;
|
|
5
|
+
readonly Gravity: Java.Wrapper<{}>;
|
|
6
|
+
readonly DialogMultiChoiceListener: Java.Wrapper<{}>;
|
|
7
|
+
readonly DialogClickListener: Java.Wrapper<{}>;
|
|
8
|
+
readonly HorizontalScrollView: Java.Wrapper<{}>;
|
|
9
|
+
readonly Context: Java.Wrapper<{}>;
|
|
10
|
+
readonly GradientDrawable: Java.Wrapper<{}>;
|
|
11
|
+
readonly BitmapFactory: Java.Wrapper<{}>;
|
|
12
|
+
readonly Base64: Java.Wrapper<{}>;
|
|
13
|
+
readonly Button: Java.Wrapper<{}>;
|
|
14
|
+
readonly Color: Java.Wrapper<{}>;
|
|
15
|
+
readonly ViewManager: Java.Wrapper<{}>;
|
|
16
|
+
readonly JString: Java.Wrapper<{}>;
|
|
17
|
+
readonly View: Java.Wrapper<{}>;
|
|
18
|
+
readonly GridLayout: Java.Wrapper<{}>;
|
|
19
|
+
readonly CheckBox: Java.Wrapper<{}>;
|
|
20
|
+
readonly SeekBar: Java.Wrapper<{}>;
|
|
21
|
+
readonly Html: Java.Wrapper<{}>;
|
|
22
|
+
readonly SeekBarOnSeekBarChangeListener: Java.Wrapper<{}>;
|
|
23
|
+
readonly AdapterViewOnItemSelectedListener: Java.Wrapper<{}>;
|
|
24
|
+
readonly Spinner: Java.Wrapper<{}>;
|
|
25
|
+
readonly ArrayAdapter: Java.Wrapper<{}>;
|
|
26
|
+
readonly R_layout: Java.Wrapper<{}>;
|
|
27
|
+
readonly DialogInterfaceOnClickListener: Java.Wrapper<{}>;
|
|
28
|
+
readonly AlertDialogBuilder: Java.Wrapper<{}>;
|
|
29
|
+
readonly AlertDialog: Java.Wrapper<{}>;
|
|
30
|
+
readonly OnTouchListener: Java.Wrapper<{}>;
|
|
31
|
+
readonly MotionEvent: Java.Wrapper<{}>;
|
|
32
|
+
readonly EditText: Java.Wrapper<{}>;
|
|
33
|
+
readonly Point: Java.Wrapper<{}>;
|
|
34
|
+
readonly DisplayMetrics: Java.Wrapper<{}>;
|
|
35
|
+
readonly TextViewBufferType: Java.Wrapper<{}>;
|
|
36
|
+
readonly InputType: Java.Wrapper<{}>;
|
|
37
|
+
readonly GridLayoutParams: Java.Wrapper<{}>;
|
|
38
|
+
readonly Switch: Java.Wrapper<{}>;
|
|
39
|
+
readonly OnCheckedChangeListener: Java.Wrapper<{}>;
|
|
40
|
+
readonly CompoundButtonOnCheckedChangeListener: Java.Wrapper<{}>;
|
|
41
|
+
readonly TextView: Java.Wrapper<{}>;
|
|
42
|
+
readonly OnClickListener: Java.Wrapper<{}>;
|
|
43
|
+
readonly FrameLayout: Java.Wrapper<{}>;
|
|
44
|
+
readonly ViewGroupLayoutParams: Java.Wrapper<{}>;
|
|
45
|
+
readonly LayoutParams: Java.Wrapper<{}>;
|
|
46
|
+
readonly BuildVERSION: Java.Wrapper<{}>;
|
|
47
|
+
readonly LinearLayout: Java.Wrapper<{}>;
|
|
48
|
+
readonly LinearLayoutParams: Java.Wrapper<{}>;
|
|
49
|
+
readonly ScrollView: Java.Wrapper<{}>;
|
|
50
|
+
};
|
package/lib/api.js
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.API = void 0;
|
|
4
|
+
exports.API = {
|
|
5
|
+
get ImageView() {
|
|
6
|
+
return Java.use("android.widget.ImageView");
|
|
7
|
+
},
|
|
8
|
+
get ImageViewScaleType() {
|
|
9
|
+
return Java.use("android.widget.ImageView$ScaleType");
|
|
10
|
+
},
|
|
11
|
+
get FrameLayoutParams() {
|
|
12
|
+
return Java.use("android.widget.FrameLayout$LayoutParams");
|
|
13
|
+
},
|
|
14
|
+
get Gravity() {
|
|
15
|
+
return Java.use("android.view.Gravity");
|
|
16
|
+
},
|
|
17
|
+
get DialogMultiChoiceListener() {
|
|
18
|
+
return Java.use("android.content.DialogInterface$OnMultiChoiceClickListener");
|
|
19
|
+
},
|
|
20
|
+
get DialogClickListener() {
|
|
21
|
+
return Java.use("android.content.DialogInterface$OnClickListener");
|
|
22
|
+
},
|
|
23
|
+
get HorizontalScrollView() {
|
|
24
|
+
return Java.use("android.widget.HorizontalScrollView");
|
|
25
|
+
},
|
|
26
|
+
get Context() {
|
|
27
|
+
return Java.use("android.content.Context");
|
|
28
|
+
},
|
|
29
|
+
get GradientDrawable() {
|
|
30
|
+
return Java.use("android.graphics.drawable.GradientDrawable");
|
|
31
|
+
},
|
|
32
|
+
get BitmapFactory() {
|
|
33
|
+
return Java.use("android.graphics.BitmapFactory");
|
|
34
|
+
},
|
|
35
|
+
get Base64() {
|
|
36
|
+
return Java.use("android.util.Base64");
|
|
37
|
+
},
|
|
38
|
+
get Button() {
|
|
39
|
+
return Java.use("android.widget.Button");
|
|
40
|
+
},
|
|
41
|
+
get Color() {
|
|
42
|
+
return Java.use("android.graphics.Color");
|
|
43
|
+
},
|
|
44
|
+
get ViewManager() {
|
|
45
|
+
return Java.use("android.view.ViewManager");
|
|
46
|
+
},
|
|
47
|
+
get JString() {
|
|
48
|
+
return Java.use("java.lang.String");
|
|
49
|
+
},
|
|
50
|
+
get View() {
|
|
51
|
+
return Java.use("android.view.View");
|
|
52
|
+
},
|
|
53
|
+
get GridLayout() {
|
|
54
|
+
return Java.use("android.widget.GridLayout");
|
|
55
|
+
},
|
|
56
|
+
get CheckBox() {
|
|
57
|
+
return Java.use("android.widget.CheckBox");
|
|
58
|
+
},
|
|
59
|
+
get SeekBar() {
|
|
60
|
+
return Java.use("android.widget.SeekBar");
|
|
61
|
+
},
|
|
62
|
+
get Html() {
|
|
63
|
+
return Java.use("android.text.Html");
|
|
64
|
+
},
|
|
65
|
+
get SeekBarOnSeekBarChangeListener() {
|
|
66
|
+
return Java.use("android.widget.SeekBar$OnSeekBarChangeListener");
|
|
67
|
+
},
|
|
68
|
+
get AdapterViewOnItemSelectedListener() {
|
|
69
|
+
return Java.use("android.widget.AdapterView$OnItemSelectedListener");
|
|
70
|
+
},
|
|
71
|
+
get Spinner() {
|
|
72
|
+
return Java.use("android.widget.Spinner");
|
|
73
|
+
},
|
|
74
|
+
get ArrayAdapter() {
|
|
75
|
+
return Java.use("android.widget.ArrayAdapter");
|
|
76
|
+
},
|
|
77
|
+
get R_layout() {
|
|
78
|
+
return Java.use("android.R$layout");
|
|
79
|
+
},
|
|
80
|
+
get DialogInterfaceOnClickListener() {
|
|
81
|
+
return Java.use("android.content.DialogInterface$OnClickListener");
|
|
82
|
+
},
|
|
83
|
+
get AlertDialogBuilder() {
|
|
84
|
+
return Java.use("android.app.AlertDialog$Builder");
|
|
85
|
+
},
|
|
86
|
+
get AlertDialog() {
|
|
87
|
+
return Java.use("android.app.AlertDialog");
|
|
88
|
+
},
|
|
89
|
+
get OnTouchListener() {
|
|
90
|
+
return Java.use("android.view.View$OnTouchListener");
|
|
91
|
+
},
|
|
92
|
+
get MotionEvent() {
|
|
93
|
+
return Java.use("android.view.MotionEvent");
|
|
94
|
+
},
|
|
95
|
+
get EditText() {
|
|
96
|
+
return Java.use("android.widget.EditText");
|
|
97
|
+
},
|
|
98
|
+
get Point() {
|
|
99
|
+
return Java.use("android.graphics.Point");
|
|
100
|
+
},
|
|
101
|
+
get DisplayMetrics() {
|
|
102
|
+
return Java.use("android.util.DisplayMetrics");
|
|
103
|
+
},
|
|
104
|
+
get TextViewBufferType() {
|
|
105
|
+
return Java.use("android.widget.TextView$BufferType");
|
|
106
|
+
},
|
|
107
|
+
get InputType() {
|
|
108
|
+
return Java.use("android.text.InputType");
|
|
109
|
+
},
|
|
110
|
+
get GridLayoutParams() {
|
|
111
|
+
return Java.use("android.widget.GridLayout$LayoutParams");
|
|
112
|
+
},
|
|
113
|
+
get Switch() {
|
|
114
|
+
return Java.use("android.widget.Switch");
|
|
115
|
+
},
|
|
116
|
+
get OnCheckedChangeListener() {
|
|
117
|
+
return Java.use("android.widget.CompoundButton$OnCheckedChangeListener");
|
|
118
|
+
},
|
|
119
|
+
get CompoundButtonOnCheckedChangeListener() {
|
|
120
|
+
return Java.use("android.widget.CompoundButton$OnCheckedChangeListener");
|
|
121
|
+
},
|
|
122
|
+
get TextView() {
|
|
123
|
+
return Java.use("android.widget.TextView");
|
|
124
|
+
},
|
|
125
|
+
get OnClickListener() {
|
|
126
|
+
return Java.use("android.view.View$OnClickListener");
|
|
127
|
+
},
|
|
128
|
+
get FrameLayout() {
|
|
129
|
+
return Java.use("android.widget.FrameLayout");
|
|
130
|
+
},
|
|
131
|
+
get ViewGroupLayoutParams() {
|
|
132
|
+
return Java.use("android.view.ViewGroup$LayoutParams");
|
|
133
|
+
},
|
|
134
|
+
get LayoutParams() {
|
|
135
|
+
return Java.use("android.view.WindowManager$LayoutParams");
|
|
136
|
+
},
|
|
137
|
+
get BuildVERSION() {
|
|
138
|
+
return Java.use("android.os.Build$VERSION");
|
|
139
|
+
},
|
|
140
|
+
get LinearLayout() {
|
|
141
|
+
return Java.use("android.widget.LinearLayout");
|
|
142
|
+
},
|
|
143
|
+
get LinearLayoutParams() {
|
|
144
|
+
return Java.use("android.widget.LinearLayout$LayoutParams");
|
|
145
|
+
},
|
|
146
|
+
get ScrollView() {
|
|
147
|
+
return Java.use("android.widget.ScrollView");
|
|
148
|
+
},
|
|
149
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { UIComponent } from "./ui-components";
|
|
2
|
+
export declare class Button extends UIComponent {
|
|
3
|
+
private label;
|
|
4
|
+
private handler;
|
|
5
|
+
private kind;
|
|
6
|
+
constructor(id: string, label: string, kind?: "primary" | "danger");
|
|
7
|
+
protected createView(context: any): void;
|
|
8
|
+
protected updateView(): void;
|
|
9
|
+
setLabel(label: string): void;
|
|
10
|
+
setOnClick(handler: () => void): void;
|
|
11
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Button = void 0;
|
|
4
|
+
const api_1 = require("../api");
|
|
5
|
+
const style_1 = require("./style/style");
|
|
6
|
+
const ui_components_1 = require("./ui-components");
|
|
7
|
+
class Button extends ui_components_1.UIComponent {
|
|
8
|
+
constructor(id, label, kind = "primary") {
|
|
9
|
+
super(id);
|
|
10
|
+
this.handler = null;
|
|
11
|
+
this.kind = "primary";
|
|
12
|
+
this.label = label;
|
|
13
|
+
this.kind = kind;
|
|
14
|
+
this.value = null;
|
|
15
|
+
}
|
|
16
|
+
createView(context) {
|
|
17
|
+
const Button = api_1.API.Button;
|
|
18
|
+
this.view = Button.$new(context);
|
|
19
|
+
const String = api_1.API.JString;
|
|
20
|
+
this.view.setText(String.$new(this.label));
|
|
21
|
+
(0, style_1.applyStyle)(this.view, this.kind === "danger" ? "dangerButton" : "primaryButton", this.menu.options.theme);
|
|
22
|
+
const OnClickListener = api_1.API.OnClickListener;
|
|
23
|
+
const self = this;
|
|
24
|
+
const clickListener = Java.registerClass({
|
|
25
|
+
name: "com.frida.MyClickListener" +
|
|
26
|
+
Date.now() +
|
|
27
|
+
Math.random().toString(36).substring(6),
|
|
28
|
+
implements: [OnClickListener],
|
|
29
|
+
methods: {
|
|
30
|
+
onClick: function (v) {
|
|
31
|
+
self.emit("click");
|
|
32
|
+
if (self.handler) {
|
|
33
|
+
setImmediate(self.handler);
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
this.view.setOnClickListener(clickListener.$new());
|
|
39
|
+
}
|
|
40
|
+
updateView() {
|
|
41
|
+
}
|
|
42
|
+
setLabel(label) {
|
|
43
|
+
this.label = label;
|
|
44
|
+
if (!this.view) {
|
|
45
|
+
console.warn(`[Button:${this.id}] Cannot set label - view not initialized`);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
Java.scheduleOnMainThread(() => {
|
|
49
|
+
const String = api_1.API.JString;
|
|
50
|
+
this.view.setText(String.$new(label));
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
setOnClick(handler) {
|
|
54
|
+
this.handler = handler;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
exports.Button = Button;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { UIComponent } from "./ui-components";
|
|
2
|
+
export declare class Category extends UIComponent {
|
|
3
|
+
private label;
|
|
4
|
+
constructor(id: string, label: string);
|
|
5
|
+
protected createView(context: any): void;
|
|
6
|
+
protected updateView(): void;
|
|
7
|
+
setLabel(label: string): void;
|
|
8
|
+
}
|