Skip to content

Allow user to handle phone account manually #221

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 15 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,29 @@ const options = {
RNCallKeep.hasDefaultPhoneAccount(options);
```

### checkPhoneAccountEnabled

Checks if the user has set a default [phone account](https://developer.android.com/reference/android/telecom/PhoneAccount) and it's enabled.

It's useful for custom permission prompts. It should be used in pair with `registerPhoneAccount`

_This feature is available only on Android._

```js
RNCallKeep.checkPhoneAccountEnabled();
```

### registerPhoneAccount

Registers phone account manualy. It should be called before `checkPhoneAccountEnabled`.

It's useful for custom permission prompts.

_This feature is available only on Android._

```js
RNCallKeep.registerPhoneAccount();
```

## Events

Expand Down
60 changes: 57 additions & 3 deletions android/src/main/java/io/wazo/callkeep/RNCallKeepModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,11 @@
import android.telephony.TelephonyManager;
import android.util.Log;

import android.view.WindowManager;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Dynamic;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.WritableNativeMap;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
Expand Down Expand Up @@ -102,6 +104,7 @@ public class RNCallKeepModule extends ReactContextBaseJavaModule {
private boolean isReceiverRegistered = false;
private VoiceBroadcastReceiver voiceBroadcastReceiver;
private ReadableMap _settings;
private WritableMap headlessExtras;

public RNCallKeepModule(ReactApplicationContext reactContext) {
super(reactContext);
Expand All @@ -128,6 +131,11 @@ public void setup(ReadableMap options) {
}
}

@ReactMethod
public void registerPhoneAccount() {
this.registerPhoneAccount(this.getAppContext());
}

@ReactMethod
public void displayIncomingCall(String uuid, String number, String callerName) {
if (!isConnectionServiceAvailable() || !hasPhoneAccount()) {
Expand Down Expand Up @@ -262,6 +270,11 @@ public void checkDefaultPhoneAccount(Promise promise) {
promise.resolve(!hasSim || hasDefaultAccount);
}

@ReactMethod
public void checkPhoneAccountEnabled(Promise promise) {
promise.resolve(hasPhoneAccount());
}

@ReactMethod
public void setOnHold(String uuid, boolean shouldHold) {
Connection conn = VoiceConnectionService.getConnection(uuid);
Expand Down Expand Up @@ -420,15 +433,56 @@ public void backToForeground() {
Context context = getAppContext();
String packageName = context.getApplicationContext().getPackageName();
Intent focusIntent = context.getPackageManager().getLaunchIntentForPackage(packageName).cloneFilter();
Activity activity = getCurrentActivity();
boolean isOpened = activity != null;
Log.d(TAG, "backToForeground, app isOpened ?" + (isOpened ? "true" : "false"));

focusIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
if (isOpened) {
focusIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
activity.startActivity(focusIntent);
}
}

@ReactMethod
public void openAppFromHeadlessMode(String callUUID) {
Context context = getAppContext();
String packageName = context.getApplicationContext().getPackageName();
Intent focusIntent = context.getPackageManager().getLaunchIntentForPackage(packageName).cloneFilter();
Activity activity = getCurrentActivity();
activity.startActivity(focusIntent);
boolean isOpened = activity != null;

if (!isOpened) {
focusIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);

final WritableMap response = new WritableNativeMap();
response.putBoolean("openedByHeadlessTask", true);
response.putString("callUUID", callUUID);

this.headlessExtras = response;

getReactApplicationContext().startActivity(focusIntent);
}
}

@ReactMethod
public void getExtrasFromHeadlessMode(Promise promise) {
if (this.headlessExtras != null) {
promise.resolve(this.headlessExtras);

this.headlessExtras = null;

return;
}

promise.resolve(null);
}

private void registerPhoneAccount(Context appContext) {
if (!isConnectionServiceAvailable()) {
if (!isConnectionServiceAvailable() || hasPhoneAccount()) {
return;
}

Expand Down
9 changes: 9 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ export type AnswerCallPayload = { callUUID: string };
export type EndCallPayload = AnswerCallPayload;
export type DidDisplayIncomingCallPayload = string | undefined;
export type DidPerformSetMutedCallActionPayload = boolean;
export type HeadlessExtras = {
callUUID: string
}

export default class RNCallKeep {
static addEventListener(type: Events, handler: (args: any) => void) {
Expand All @@ -55,6 +58,9 @@ export default class RNCallKeep {

}

static checkPhoneAccountEnabled(): Promise<boolean>
static registerPhoneAccount(): void

static displayIncomingCall(
uuid: string,
handle: string,
Expand Down Expand Up @@ -175,4 +181,7 @@ export default class RNCallKeep {
static backToForeground() {

}

static openAppFromHeadlessMode(callUUID: string): void
static getExtrasFromHeadlessMode(): Promise<HeadlessExtras>
}
38 changes: 38 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,22 @@ class RNCallKeep {
return this._setupIOS(options.ios);
};

checkPhoneAccountEnabled = async () => {
if (isIOS) {
return;
}

return RNCallKeepModule.checkPhoneAccountEnabled();
}

registerPhoneAccount = () => {
if (isIOS) {
return;
}

RNCallKeepModule.registerPhoneAccount();
}

hasDefaultPhoneAccount = async (options) => {
if (!isIOS) {
return this._hasDefaultPhoneAccount(options);
Expand Down Expand Up @@ -184,6 +200,12 @@ class RNCallKeep {
_setupAndroid = async (options) => {
RNCallKeepModule.setup(options);

const hasDefaultAccount = await RNCallKeepModule.checkPhoneAccountEnabled()

if (hasDefaultAccount) {
return true
}

const showAccountAlert = await RNCallKeepModule.checkPhoneAccountPermission(options.additionalPermissions || []);
const shouldOpenAccounts = await this._alert(options, showAccountAlert);

Expand Down Expand Up @@ -234,6 +256,22 @@ class RNCallKeep {
NativeModules.RNCallKeep.backToForeground();
}

openAppFromHeadlessMode(callUUID) {
if (isIOS) {
return;
}

NativeModules.RNCallKeep.openAppFromHeadlessMode(callUUID);
}

async getExtrasFromHeadlessMode() {
if (isIOS) {
return;
}

return NativeModules.RNCallKeep.getExtrasFromHeadlessMode();
}

}

export default new RNCallKeep();