Skip to content
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

CallInfo API #15651

Closed
wants to merge 4 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
74 changes: 74 additions & 0 deletions Libraries/Utilities/CallInfo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule CallInfo
* @flow
*/
'use strict';

const Map = require('Map');
const NativeEventEmitter = require('NativeEventEmitter');
const NativeModules = require('NativeModules');
const Platform = require('Platform');
const RCTCallInfo = NativeModules.CallInfo;

const CallInfoEventEmitter = new NativeEventEmitter(RCTCallInfo);

const CALL_STATE_EVENT = 'callStateDidChange';

const _subscriptions = new Map();

/**
* CallInfo exposes info about call status
*/
const CallInfo = {
/**
* Adds an event handler
*/
addEventListener(
eventName: string,
handler: Function
): {remove: () => void} {
let listener;
if (eventName === 'change') {
listener = CallInfoEventEmitter.addListener(
CALL_STATE_EVENT,
(appStateData) => {
handler(appStateData.phone_state);
}
);
} else {
console.warn('Trying to subscribe to unknown event: "' + eventName + '"');
return {
remove: () => {}
};
}

_subscriptions.set(handler, listener);
return {
remove: () => CallInfo.removeEventListener(eventName, handler)
};
},

/**
* Removes the listener for call status changes.
*/
removeEventListener(
eventName: string,
handler: Function
): void {
const listener = _subscriptions.get(handler);
if (!listener) {
return;
}
listener.remove();
_subscriptions.delete(handler);
}
};

module.exports = CallInfo;
1 change: 1 addition & 0 deletions Libraries/react-native/react-native-implementation.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ const ReactNative = {
get Linking() { return require('Linking'); },
get NativeEventEmitter() { return require('NativeEventEmitter'); },
get NetInfo() { return require('NetInfo'); },
get CallInfo() { return require('CallInfo'); },
get PanResponder() { return require('PanResponder'); },
get PermissionsAndroid() { return require('PermissionsAndroid'); },
get PixelRatio() { return require('PixelRatio'); },
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
include_defs("//ReactAndroid/DEFS")

android_library(
name = "callinfo",
srcs = glob(["**/*.java"]),
provided_deps = [
react_native_dep("third-party/android/support/v4:lib-support-v4"),
],
visibility = [
"PUBLIC",
],
deps = [
react_native_dep("libraries/fbcore/src/main/java/com/facebook/common/logging:logging"),
react_native_dep("third-party/java/infer-annotations:infer-annotations"),
react_native_dep("third-party/java/jsr-305:jsr-305"),
react_native_target("java/com/facebook/react/bridge:bridge"),
react_native_target("java/com/facebook/react/common:common"),
react_native_target("java/com/facebook/react/module/annotations:annotations"),
react_native_target("java/com/facebook/react/modules/core:core"),
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/

package com.facebook.react.modules.callinfo;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.telephony.TelephonyManager;

import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeMap;
import com.facebook.react.module.annotations.ReactModule;

import static com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter;

/**
* Module that monitors and provides information about the call state of the device.
*/
@ReactModule(name = "CallInfo")
public class CallInfoModule extends ReactContextBaseJavaModule
implements LifecycleEventListener {

private static final String MISSING_PERMISSION_MESSAGE =
"To use CallInfo on Android, add the following to your AndroidManifest.xml:\n" +
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\" />";

private static final String ERROR_MISSING_PERMISSION = "E_MISSING_PERMISSION";

private static final String ACTION_PHONE_STATE = "android.intent.action.PHONE_STATE";

private static final String PHONE_STATE_UNKNOWN = "unknown";
private static final String PHONE_STATE_RINGING = "ringing";
private static final String PHONE_STATE_OFFHOOK = "offhook";
private static final String PHONE_STATE_IDLE = "idle";

private final CallBroadcastReceiver mCallBroadcastReceiver;
private boolean mNoCallInfoPermission = false;

private String mPhoneState = PHONE_STATE_UNKNOWN;

public CallInfoModule(ReactApplicationContext reactContext) {
super(reactContext);
mCallBroadcastReceiver = new CallBroadcastReceiver();
}

@Override
public void onHostResume() {
registerReceiver();
}

@Override
public void onHostPause() {
unregisterReceiver();
}

@Override
public void onHostDestroy() {
}

@Override
public void initialize() {
getReactApplicationContext().addLifecycleEventListener(this);
}

@Override
public String getName() {
return "CallInfo";
}

@ReactMethod
public void getCurrentState(Promise promise) {
if (mNoCallInfoPermission) {
promise.reject(ERROR_MISSING_PERMISSION, MISSING_PERMISSION_MESSAGE, null);
return;
}
promise.resolve(createCallInfoEventMap());
}

private void registerReceiver() {
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_PHONE_STATE);
getReactApplicationContext().registerReceiver(mCallBroadcastReceiver, filter);
mCallBroadcastReceiver.setRegistered(true);
}

private void unregisterReceiver() {
if (mCallBroadcastReceiver.isRegistered()) {
getReactApplicationContext().unregisterReceiver(mCallBroadcastReceiver);
mCallBroadcastReceiver.setRegistered(false);
}
}

private void sendCallStateChangedEvent() {
getReactApplicationContext().getJSModule(RCTDeviceEventEmitter.class)
.emit("callStateDidChange", createCallInfoEventMap());
}

private WritableMap createCallInfoEventMap() {
WritableMap event = new WritableNativeMap();
event.putString("phone_state", mPhoneState);
return event;
}

/**
* Class that receives intents whenever the call state changes.
*/
private class CallBroadcastReceiver extends BroadcastReceiver {
private boolean isRegistered = false;

public void setRegistered(boolean registered) {
isRegistered = registered;
}

public boolean isRegistered() {
return isRegistered;
}

@Override
public void onReceive(Context context, Intent intent) {
String phoneState = intent.getStringExtra("state");

if (phoneState.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
mPhoneState = PHONE_STATE_RINGING;
} else if (phoneState.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) {
mPhoneState = PHONE_STATE_OFFHOOK;
} else if (phoneState.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
mPhoneState = PHONE_STATE_IDLE;
}

sendCallStateChangedEvent();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import com.facebook.react.modules.intent.IntentModule;
import com.facebook.react.modules.location.LocationModule;
import com.facebook.react.modules.netinfo.NetInfoModule;
import com.facebook.react.modules.callinfo.CallInfoModule;
import com.facebook.react.modules.network.NetworkingModule;
import com.facebook.react.modules.permissions.PermissionsModule;
import com.facebook.react.modules.share.ShareModule;
Expand Down Expand Up @@ -244,6 +245,14 @@ public NativeModule get() {
return new NetInfoModule(context);
}
}),
new ModuleSpec(
CallInfoModule.class,
new Provider<NativeModule>() {
@Override
public NativeModule get() {
return new CallInfoModule(context);
}
}),
new ModuleSpec(
PermissionsModule.class,
new Provider<NativeModule>() {
Expand Down