Skip to content

Commit bf4cc78

Browse files
xaionaro@dx.centerxaionaro@dx.center
authored andcommitted
feat(examples): make all 16 stub examples interact meaningfully
Replace stub implementations with real API calls: - settings: read brightness, font scale, android_id, device name - clipboard: set/get text round-trip - display: query size, density, refresh rate, rotation - telephony: phone type, SIM state, network operator - storage: primary volume state, UUID, emulated/removable - health: check Health Connect availability - keystore: list AndroidKeyStore aliases - preferences: write/read 5 typed values - accounts: list accounts and authenticator types - telecom: default dialer, phone accounts, call state - inputmethod: list enabled/installed IMEs - companion: list companion device associations - session: list active media sessions - camera: enumerate cameras with lens facing - resolver: query settings content provider - permission: check 8 common permissions Also extract shared GetAppContext into exampleui package to eliminate copy-paste across all examples.
1 parent d346381 commit bf4cc78

42 files changed

Lines changed: 1420 additions & 1755 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

examples/accounts/main.go

Lines changed: 59 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
// Command accounts demonstrates querying Android device accounts
44
// using the accounts package, which wraps android.accounts.AccountManager.
5-
// It is built as a c-shared library and packaged into an APK using
6-
// the shared apk.mk infrastructure.
75
package main
86

97
/*
@@ -21,10 +19,9 @@ import (
2119
"unsafe"
2220

2321
"github.com/AndroidGoLab/jni"
22+
"github.com/AndroidGoLab/jni/accounts"
2423
"github.com/AndroidGoLab/jni/capi"
2524
"github.com/AndroidGoLab/jni/exampleui"
26-
"github.com/AndroidGoLab/jni/accounts"
27-
"github.com/AndroidGoLab/jni/app"
2825
)
2926

3027
func main() {}
@@ -53,70 +50,79 @@ func goOnNativeWindowCreated(activity *C.ANativeActivity, window *C.ANativeWindo
5350
}
5451

5552
func run(vm *jni.VM, output *bytes.Buffer) error {
56-
_, err := getAppContext(vm)
53+
ctx, err := exampleui.GetAppContext(vm)
5754
if err != nil {
5855
return fmt.Errorf("get context: %w", err)
5956
}
57+
defer ctx.Close()
6058

61-
// The accounts package wraps android.accounts.AccountManager.
62-
// The Manager type provides access to device accounts through
63-
// unexported methods (getAccountsRaw, getAccountsByTypeRaw,
64-
// getAuthTokenRaw, invalidateAuthTokenRaw) which are intended
65-
// to be wrapped by higher-level helpers.
66-
//
67-
// The Manager struct has exported fields:
68-
// VM *jni.VM
69-
// Obj *jni.GlobalRef
70-
//
71-
// Manager is obtained via the static factory AccountManager.get(Context),
72-
// exposed as the unexported getManagerRaw method.
73-
74-
// Account is a data class with exported fields extracted from
75-
// android.accounts.Account Java objects.
76-
// Account wraps android.accounts.Account. Its fields (VM, Obj) hold
77-
// references to the Java object. Name and Type are accessed via JNI
78-
// methods (DescribeContents, Equals, HashCode, etc.).
79-
var acct accounts.Account
80-
_ = acct
81-
fmt.Fprintln(output, "Account type available with DescribeContents, Equals, HashCode methods")
82-
83-
fmt.Fprintln(output, "AccountManager raw methods: getManagerRaw, getAccountsRaw, getAccountsByTypeRaw, getAuthTokenRaw, invalidateAuthTokenRaw")
59+
mgr, err := accounts.NewAccountManager(ctx)
60+
if err != nil {
61+
return fmt.Errorf("NewAccountManager: %w", err)
62+
}
63+
defer mgr.Close()
8464

85-
return nil
86-
}
65+
fmt.Fprintln(output, "=== Device Accounts ===")
8766

88-
// getAppContext obtains an Android Context via ActivityThread.currentApplication().
89-
func getAppContext(vm *jni.VM) (*app.Context, error) {
90-
var ctx app.Context
91-
ctx.VM = vm
67+
acctArray, err := mgr.GetAccounts()
68+
if err != nil {
69+
fmt.Fprintf(output, "GetAccounts: %v\n", err)
70+
return nil
71+
}
9272

93-
err := vm.Do(func(env *jni.Env) error {
94-
if err := app.Init(env); err != nil {
95-
return err
73+
var acctCount int32
74+
err = vm.Do(func(env *jni.Env) error {
75+
if acctArray == nil {
76+
return nil
9677
}
78+
acctCount = env.GetArrayLength((*jni.Array)(unsafe.Pointer(acctArray)))
79+
return nil
80+
})
81+
if err != nil {
82+
return fmt.Errorf("get array length: %w", err)
83+
}
9784

98-
atClass, err := env.FindClass("android/app/ActivityThread")
85+
fmt.Fprintf(output, "Account count: %d\n", acctCount)
86+
87+
for i := int32(0); i < acctCount; i++ {
88+
acct := accounts.Account{VM: vm}
89+
err := vm.Do(func(env *jni.Env) error {
90+
elem, err := env.GetObjectArrayElement((*jni.ObjectArray)(unsafe.Pointer(acctArray)), i)
91+
if err != nil {
92+
return fmt.Errorf("get element %d: %w", i, err)
93+
}
94+
acct.Obj = env.NewGlobalRef(elem)
95+
return nil
96+
})
9997
if err != nil {
100-
return fmt.Errorf("find ActivityThread: %w", err)
98+
fmt.Fprintf(output, " [%d] error: %v\n", i, err)
99+
continue
101100
}
102101

103-
curAppMid, err := env.GetStaticMethodID(atClass, "currentApplication", "()Landroid/app/Application;")
102+
str, err := acct.ToString()
104103
if err != nil {
105-
return fmt.Errorf("get currentApplication: %w", err)
106-
}
107-
appObj, err := env.CallStaticObjectMethod(atClass, curAppMid)
108-
if err != nil {
109-
return fmt.Errorf("call currentApplication: %w", err)
110-
}
111-
if appObj == nil || appObj.Ref() == 0 {
112-
return fmt.Errorf("currentApplication returned null")
104+
fmt.Fprintf(output, " [%d] ToString err: %v\n", i, err)
105+
} else {
106+
fmt.Fprintf(output, " [%d] %s\n", i, str)
113107
}
108+
}
114109

115-
ctx.Obj = env.NewGlobalRef(appObj)
116-
return nil
117-
})
110+
authArray, err := mgr.GetAuthenticatorTypes()
118111
if err != nil {
119-
return nil, err
112+
fmt.Fprintf(output, "GetAuthenticatorTypes: %v\n", err)
113+
return nil
120114
}
121-
return &ctx, nil
115+
116+
var authCount int32
117+
_ = vm.Do(func(env *jni.Env) error {
118+
if authArray == nil {
119+
return nil
120+
}
121+
authCount = env.GetArrayLength((*jni.Array)(unsafe.Pointer(authArray)))
122+
return nil
123+
})
124+
125+
fmt.Fprintf(output, "\nAuthenticator types: %d\n", authCount)
126+
127+
return nil
122128
}

examples/alarm/main.go

Lines changed: 1 addition & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ func goOnNativeWindowCreated(activity *C.ANativeActivity, window *C.ANativeWindo
7070
}
7171

7272
func run(vm *jni.VM, output *bytes.Buffer) error {
73-
ctx, err := getAppContext(vm)
73+
ctx, err := exampleui.GetAppContext(vm)
7474
if err != nil {
7575
return fmt.Errorf("get context: %w", err)
7676
}
@@ -221,34 +221,3 @@ func playAlarmRingtone(vm *jni.VM, appCtx *jni.Object) error {
221221

222222
return nil
223223
}
224-
225-
func getAppContext(vm *jni.VM) (*app.Context, error) {
226-
var ctx app.Context
227-
ctx.VM = vm
228-
err := vm.Do(func(env *jni.Env) error {
229-
if err := app.Init(env); err != nil {
230-
return err
231-
}
232-
atClass, err := env.FindClass("android/app/ActivityThread")
233-
if err != nil {
234-
return err
235-
}
236-
mid, err := env.GetStaticMethodID(atClass, "currentApplication", "()Landroid/app/Application;")
237-
if err != nil {
238-
return err
239-
}
240-
appObj, err := env.CallStaticObjectMethod(atClass, mid)
241-
if err != nil {
242-
return err
243-
}
244-
if appObj == nil || appObj.Ref() == 0 {
245-
return fmt.Errorf("currentApplication returned null")
246-
}
247-
ctx.Obj = env.NewGlobalRef(appObj)
248-
return nil
249-
})
250-
if err != nil {
251-
return nil, err
252-
}
253-
return &ctx, nil
254-
}

examples/app_framework/main.go

Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func goOnNativeWindowCreated(activity *C.ANativeActivity, window *C.ANativeWindo
5454

5555
func run(vm *jni.VM, output *bytes.Buffer) error {
5656
// --- Context ---
57-
ctx, err := getAppContext(vm)
57+
ctx, err := exampleui.GetAppContext(vm)
5858
if err != nil {
5959
return fmt.Errorf("get context: %w", err)
6060
}
@@ -136,39 +136,3 @@ func run(vm *jni.VM, output *bytes.Buffer) error {
136136

137137
return nil
138138
}
139-
140-
// getAppContext obtains an Android Context via ActivityThread.currentApplication().
141-
func getAppContext(vm *jni.VM) (*app.Context, error) {
142-
var ctx app.Context
143-
ctx.VM = vm
144-
145-
err := vm.Do(func(env *jni.Env) error {
146-
if err := app.Init(env); err != nil {
147-
return err
148-
}
149-
150-
atClass, err := env.FindClass("android/app/ActivityThread")
151-
if err != nil {
152-
return fmt.Errorf("find ActivityThread: %w", err)
153-
}
154-
155-
curAppMid, err := env.GetStaticMethodID(atClass, "currentApplication", "()Landroid/app/Application;")
156-
if err != nil {
157-
return fmt.Errorf("get currentApplication: %w", err)
158-
}
159-
appObj, err := env.CallStaticObjectMethod(atClass, curAppMid)
160-
if err != nil {
161-
return fmt.Errorf("call currentApplication: %w", err)
162-
}
163-
if appObj == nil || appObj.Ref() == 0 {
164-
return fmt.Errorf("currentApplication returned null")
165-
}
166-
167-
ctx.Obj = env.NewGlobalRef(appObj)
168-
return nil
169-
})
170-
if err != nil {
171-
return nil, err
172-
}
173-
return &ctx, nil
174-
}

examples/audiomanager/main.go

Lines changed: 2 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import (
2727
"github.com/AndroidGoLab/jni"
2828
"github.com/AndroidGoLab/jni/capi"
2929
"github.com/AndroidGoLab/jni/exampleui"
30-
"github.com/AndroidGoLab/jni/app"
3130
"github.com/AndroidGoLab/jni/media/audiomanager"
3231
)
3332

@@ -57,15 +56,15 @@ func goOnNativeWindowCreated(activity *C.ANativeActivity, window *C.ANativeWindo
5756
}
5857

5958
func run(vm *jni.VM, output *bytes.Buffer) error {
60-
ctx, err := getAppContext(vm)
59+
ctx, err := exampleui.GetAppContext(vm)
6160
if err != nil {
6261
return fmt.Errorf("get context: %w", err)
6362
}
6463
defer ctx.Close()
6564

6665
mgr, err := audiomanager.NewAudioManager(ctx)
6766
if err != nil {
68-
return fmt.Errorf("audiomanager.NewAudioManager: %v", err)
67+
return fmt.Errorf("audiomanager.NewAudioManager: %w", err)
6968
}
7069
defer mgr.Close()
7170

@@ -105,39 +104,3 @@ func run(vm *jni.VM, output *bytes.Buffer) error {
105104

106105
return nil
107106
}
108-
109-
// getAppContext obtains an Android Context via ActivityThread.currentApplication().
110-
func getAppContext(vm *jni.VM) (*app.Context, error) {
111-
var ctx app.Context
112-
ctx.VM = vm
113-
114-
err := vm.Do(func(env *jni.Env) error {
115-
if err := app.Init(env); err != nil {
116-
return err
117-
}
118-
119-
atClass, err := env.FindClass("android/app/ActivityThread")
120-
if err != nil {
121-
return fmt.Errorf("find ActivityThread: %w", err)
122-
}
123-
124-
curAppMid, err := env.GetStaticMethodID(atClass, "currentApplication", "()Landroid/app/Application;")
125-
if err != nil {
126-
return fmt.Errorf("get currentApplication: %w", err)
127-
}
128-
appObj, err := env.CallStaticObjectMethod(atClass, curAppMid)
129-
if err != nil {
130-
return fmt.Errorf("call currentApplication: %w", err)
131-
}
132-
if appObj == nil || appObj.Ref() == 0 {
133-
return fmt.Errorf("currentApplication returned null")
134-
}
135-
136-
ctx.Obj = env.NewGlobalRef(appObj)
137-
return nil
138-
})
139-
if err != nil {
140-
return nil, err
141-
}
142-
return &ctx, nil
143-
}

examples/battery/main.go

Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ func goOnNativeWindowCreated(activity *C.ANativeActivity, window *C.ANativeWindo
5656
}
5757

5858
func run(vm *jni.VM, output *bytes.Buffer) error {
59-
ctx, err := getAppContext(vm)
59+
ctx, err := exampleui.GetAppContext(vm)
6060
if err != nil {
6161
return fmt.Errorf("get context: %w", err)
6262
}
@@ -103,39 +103,3 @@ func run(vm *jni.VM, output *bytes.Buffer) error {
103103

104104
return nil
105105
}
106-
107-
// getAppContext obtains an Android Context via ActivityThread.currentApplication().
108-
func getAppContext(vm *jni.VM) (*app.Context, error) {
109-
var ctx app.Context
110-
ctx.VM = vm
111-
112-
err := vm.Do(func(env *jni.Env) error {
113-
if err := app.Init(env); err != nil {
114-
return err
115-
}
116-
117-
atClass, err := env.FindClass("android/app/ActivityThread")
118-
if err != nil {
119-
return fmt.Errorf("find ActivityThread: %w", err)
120-
}
121-
122-
curAppMid, err := env.GetStaticMethodID(atClass, "currentApplication", "()Landroid/app/Application;")
123-
if err != nil {
124-
return fmt.Errorf("get currentApplication: %w", err)
125-
}
126-
appObj, err := env.CallStaticObjectMethod(atClass, curAppMid)
127-
if err != nil {
128-
return fmt.Errorf("call currentApplication: %w", err)
129-
}
130-
if appObj == nil || appObj.Ref() == 0 {
131-
return fmt.Errorf("currentApplication returned null")
132-
}
133-
134-
ctx.Obj = env.NewGlobalRef(appObj)
135-
return nil
136-
})
137-
if err != nil {
138-
return nil, err
139-
}
140-
return &ctx, nil
141-
}

0 commit comments

Comments
 (0)