Commit a6be43fa authored by Wei Han's avatar Wei Han

ios progress

parent 33bf9979
......@@ -103,25 +103,6 @@ export default function App() {
))}
{allGranted && <Text style={styles.granted}>All permissions granted ✅</Text>}
<Button title="Check Again" onPress={checkAllPermissions} />
<Button
title="Simulate VIP Call"
onPress={async () => {
const number = '+60123456789';
const name = 'VIP User';
// Save VIP info in AsyncStorage + native storage
await saveVIPNumber(name, number);
// Call native module to start OverlayService (simulate incoming call)
if (NativeModules.VIPStorage?.simulateVipCall) {
NativeModules.VIPStorage.simulateVipCall(number, name);
} else {
console.warn('simulateVipCall not implemented in NativeModules.');
}
Alert.alert('Simulated VIP call', `${name} (${number})`);
}}
/>
</View>
);
}
......
......@@ -25,11 +25,11 @@ Please follow this installation instruction.
> :information_source: **Note:** If you hit error permission denied, please execute `chmod +x gradlew`
<!-- 4. Pod install for iOS :
4. Pod install for iOS :
- Go into iOS directory: `cd ios`
- Install pod: `pod install`
- After completion, return to main directory: `cd ../` -->
- After completion, return to main directory: `cd ../`
5. Finish installation :clap:
......@@ -41,12 +41,12 @@ Below is all command that use to execute react native project for android and iO
1. Run : `npx react-native run-android`
<!-- ## iOS
## iOS
1. go to iOS directory by execute : `cd ios` <br>
2. open xCode workspace by execute : `Runner.xcworkspace` <br>
3. clean app by go to Product > Clean Build Folder...
4. run app by go to Product > Build -->
4. run app by go to Product > Build
## Expected behavior
- When user's phone is called, alert shows up showing the caller number + who the caller is
......
......@@ -7,6 +7,7 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.ACTION_MANAGE_OVERLAY_PERMISSION" />
<application
android:name=".MainApplication"
......
......@@ -4,30 +4,21 @@ import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.app.role.RoleManager
import androidx.activity.ComponentActivity
import androidx.activity.result.contract.ActivityResultContracts
import com.whoscall.databinding.ActivityMainBinding
import android.content.SharedPreferences
import android.util.Log
import com.facebook.react.ReactActivity
class MainActivity : ComponentActivity() {
private lateinit var binding: ActivityMainBinding
class MainActivity : ReactActivity() {
private val roleLauncher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { /* no-op */ }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.btnOverlay.setOnClickListener { requestOverlay() }
binding.btnRole.setOnClickListener { requestCallScreeningRoleIfNeeded() }
override fun getMainComponentName(): String {
// 👇 must match what you registered in index.js
return "whoscall"
}
private fun requestOverlay() {
......@@ -50,15 +41,12 @@ class MainActivity : ComponentActivity() {
}
private fun simulateVipCall() {
// Example VIP number and name
val vipNumber = "+60189884118"
val vipName = "Wei Yi"
// Save to SharedPreferences
val prefs = getSharedPreferences("WhoscallPrefs", MODE_PRIVATE)
prefs.edit().putString(vipNumber, vipName).apply()
// Start overlay service directly
val overlayIntent = Intent(this, OverlayService::class.java).apply {
putExtra("number", vipNumber)
putExtra("displayName", vipName)
......
......@@ -19,6 +19,7 @@ class MainApplication : Application(), ReactApplication {
// Packages that cannot be autolinked yet can be added manually here, for example:
// add(MyReactNativePackage())
add(StoragePackage())
}
override fun getJSMainModuleName(): String = "index"
......
package com.whoscall
import android.content.Context
import android.os.Build
import android.provider.Settings
object OverlayPermissionChecker {
/**
* Returns true if the app has permission to draw over other apps
*/
fun hasOverlayPermission(context: Context): Boolean{
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Settings.canDrawOverlays(context)
} else {
true //Automaticallt allowed on older android versions
}
}
}
\ No newline at end of file
......@@ -25,21 +25,4 @@ class StorageModule(reactContext: ReactApplicationContext) :
promise.reject("SAVE_ERROR", e)
}
}
@ReactMethod
fun simulateVipCall(number: String, name: String) {
Log.d("VIPStorage", "Simulating VIP call: $name ($number)")
val context = reactApplicationContext
// Save VIP first
prefs.edit().putString(number, name).apply()
// Start OverlayService
val intent = Intent(context, OverlayService::class.java).apply {
putExtra("number", number)
putExtra("displayName", name)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
context.startService(intent)
}
}
......@@ -4,3 +4,7 @@ extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autoli
rootProject.name = 'whoscall'
include ':app'
includeBuild('../node_modules/@react-native/gradle-plugin')
include ':rn-android-overlay-permission'
project(':rn-android-overlay-permission').projectDir = new File(
rootProject.projectDir, '../node_modules/rn-android-overlay-permission/android'
)
\ No newline at end of file
......@@ -32,4 +32,10 @@ target 'whoscall' do
# :ccache_enabled => true
)
end
permissions_path = '../node_modules/react-native-permissions/ios'
pod 'Permission-Contacts', :path => "#{permissions_path}/Contacts.podspec"
pod 'Permission-Phone', :path => "#{permissions_path}/Phone.podspec"
pod 'Permission-Notifications', :path => "#{permissions_path}/Notifications.podspec"
end
This diff is collapsed.
This diff is collapsed.
......@@ -31,10 +31,15 @@
<key>NSAllowsLocalNetworking</key>
<true/>
</dict>
<key>NSUserActivityTypes</key>
<array>
<string>INStartAudioCallIntent</string>
<string>INStartVideoCallIntent</string>
</array>
<key>NSLocationWhenInUseUsageDescription</key>
<string></string>
<key>RCTNewArchEnabled</key>
<false/>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
......
......@@ -14,6 +14,14 @@
</dict>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategorySystemBootTime</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>35F9.1</string>
</array>
</dict>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
......@@ -22,10 +30,10 @@
</dict>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategorySystemBootTime</string>
<string>NSPrivacyAccessedAPICategoryDiskSpace</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>35F9.1</string>
<string>85F4.1</string>
</array>
</dict>
</array>
......
import Foundation
import CallKit
class CallDirectoryHandler: CXCallDirectoryProvider {
override func beginRequest(with context: CXCallDirectoryExtensionContext) {
context.delegate = self
// Add numbers to identify (VIPs, spam, etc.)
addIdentificationNumbers(to: context)
// Add numbers to block (if you want)
// addBlockingNumbers(to: context)
context.completeRequest()
}
private func addIdentificationNumbers(to context: CXCallDirectoryExtensionContext) {
// Example: add VIP numbers
// Numbers must be E.164 format (+60 for Malaysia)
let vipNumbers: [(number: Int64, label: String)] = [
(60189884118, "VIP: Wei Yi"),
(60123456789, "Spam Caller"),
]
for entry in vipNumbers {
context.addIdentificationEntry(withNextSequentialPhoneNumber: entry.number,
label: entry.label)
}
}
private func addBlockingNumbers(to context: CXCallDirectoryExtensionContext) {
// Example: block a number
let blockedNumbers: [Int64] = [
60199998888
]
for number in blockedNumbers {
context.addBlockingEntry(withNextSequentialPhoneNumber: number)
}
}
}
// Optional: log errors
extension CallDirectoryHandler: CXCallDirectoryExtensionContextDelegate {
func requestFailed(for extensionContext: CXCallDirectoryExtensionContext, withError error: Error) {
NSLog("Call Directory extension error: \(error.localizedDescription)")
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.callkit.call-directory</string>
<key>NSExtensionPrincipalClass</key>
<string>$(PRODUCT_MODULE_NAME).CallDirectoryHandler</string>
</dict>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>CXCallDirectoryExtensionAttributes</key>
<dict>
<key>CXCallDirectoryExtensionIdentifier</key>
<string>com.yourapp.callid</string>
</dict>
</dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.callkit.call-directory</string>
<key>NSExtensionPrincipalClass</key>
<string>$(PRODUCT_MODULE_NAME).CallDirectoryHandler</string>
</dict>
</dict>
</plist>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment