I do everything according to the documentation, but my application crashes. Function triggering when there is a phone call I want to make. I did catch the call with Broadreciver. I did show on the screen with a toast message. But I can not send it to the service I created for headless js and run it. I can't debug or know the method
index.js
import {AppRegistry} from 'react-native';
import App from './App';
import {name as appName} from './app.json';
const Fnc = async (taskData) => {
console.log('data',taskData);
}
AppRegistry.registerComponent(appName, () => App);
AppRegistry.registerHeadlessTask('CallListener', () => Fnc);
AndroidManifest.xml
<application>
...
<receiver android:name=".CallReceiver">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
<service android:name=".CallService" android:enabled="true" />
</application>
CallReceiver.java
public class CallReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
try {
if (!isAppOnForeground((context))) {
if(intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_RINGING)){
String number = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
Intent serviceIntent = new Intent(context, CallService.class);
//Bundle bundle = new Bundle();
//bundle.putString("even", "okkk");
showText(context, "Callsss Ring...No: " + number);
serviceIntent.putExtra("event", "Incoming");
// serviceIntent.putExtra("event", "Incoming");
// serviceIntent.putExtras(bundle);
context.startService(serviceIntent);
HeadlessJsTaskService.acquireWakeLockNow(context);
}
}
}catch (Exception ex){
Log.i("ex", ex.getMessage());
}
}
private boolean isAppOnForeground(Context context) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> appProcesses =
activityManager.getRunningAppProcesses();
if (appProcesses == null) {
return false;
}
final String packageName = context.getPackageName();
for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.importance ==
ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND &&
appProcess.processName.equals(packageName)) {
return true;
}
}
return false;
}
void showText(Context context, String message){
Toast toast = Toast.makeText(context, message, Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();
}
}
CallService.java
public class CallService extends HeadlessJsTaskService {
#Override
protected #Nullable HeadlessJsTaskConfig getTaskConfig(Intent intent) {
Bundle extras = intent.getExtras();
WritableMap data = extras != null ? Arguments.fromBundle(extras) : null;
return new HeadlessJsTaskConfig(
"CallListener",
data,
5000, // timeout for the task
false // optional: defines whether or not the task is allowed in foreground. Default is false,
);
}
}
I've been researching for days, but I can't find the problem
Related
I am trying to auth google user in WebView, I found a good solution for these days, it works fine for google login, but I cannot disable dialog in other urls like (, sms: , smsto:)
Example Situation: User click on telephone number in my app, it will open the phone dial, but when he returns back.. there is a empty dialog window with close button, i use it for google login with JS.
How can i close this dialog message inside the shouldOverrideUrlLoading()? Or is there any better solution to not open other links in the dialog? How can i improve my code to solve my problem? Thank you guys!
package com.example.app;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.net.http.SslCertificate;
import android.net.http.SslError;
import android.os.Bundle;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.webkit.CookieManager;
import android.webkit.JsResult;
import android.webkit.SslErrorHandler;
import android.webkit.URLUtil;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import java.lang.reflect.Field;
import java.security.cert.X509Certificate;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class MainActivity extends Activity {
private WebView mWebView;
private String userAgent;
private Context contextPop;
private WebView webViewPop;
private AlertDialog builder;
#Override
#SuppressLint("SetJavaScriptEnabled")
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
userAgent = System.getProperty("http.agent");
mWebView = findViewById(R.id.activity_main_webview);
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setDomStorageEnabled(true);
webSettings.setUseWideViewPort(true);
webSettings.setAppCacheEnabled(false);
webSettings.setAllowFileAccess(true);
webSettings.setAllowFileAccessFromFileURLs(true);
webSettings.setAllowUniversalAccessFromFileURLs(true);
webSettings.setUserAgentString(userAgent+ "com.example.app");
mWebView.clearCache(true);
// REMOTE RESOURCE
mWebView.loadUrl("https://example.eu/");
mWebView.setWebChromeClient(new CustomChromeClient());
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
webSettings.setSupportMultipleWindows(true);
contextPop = this.getApplicationContext();
// LOCAL RESOURCE
// mWebView.loadUrl("file:///android_asset/index.html");
}
#Override
public void onBackPressed() {
if(mWebView.canGoBack()) {
mWebView.goBack();
} else {
super.onBackPressed();
}
}
final Context myApp = this;
class CustomChromeClient extends WebChromeClient {
#Override
public boolean onCreateWindow(WebView view, boolean isDialog,
boolean isUserGesture, Message resultMsg) {
webViewPop = new WebView(contextPop);
webViewPop.setWebViewClient(new WebViewClient() {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
String host = Uri.parse(url).getHost();
if (url.startsWith("tel:") || url.startsWith("sms:") || url.startsWith("smsto:") || url.startsWith("mms:") || url.startsWith("mmsto:"))
{
webViewPop.destroy();
Intent intent = new Intent(Intent.ACTION_VIEW,Uri.parse(url));
startActivity(intent);
return true;
}
//Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
//view.getContext().startActivity(intent);
return false;
}
});
// Enable Cookies
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.setAcceptCookie(true);
if (android.os.Build.VERSION.SDK_INT >= 21) {
cookieManager.setAcceptThirdPartyCookies(webViewPop, true);
cookieManager.setAcceptThirdPartyCookies(mWebView, true);
}
WebSettings popSettings = webViewPop.getSettings();
// WebView tweaks for popups
webViewPop.setVerticalScrollBarEnabled(false);
webViewPop.setHorizontalScrollBarEnabled(false);
popSettings.setJavaScriptEnabled(true);
popSettings.setSaveFormData(true);
popSettings.setEnableSmoothTransition(true);
// Set User Agent
popSettings.setUserAgentString(userAgent + "Your App Info/Version");
// to support content re-layout for redirects
popSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
// handle new popups
webViewPop.setWebChromeClient(new CustomChromeClient());
// set the WebView as the AlertDialog.Builder’s view
builder = new AlertDialog.Builder(MainActivity.this, AlertDialog.THEME_DEVICE_DEFAULT_LIGHT).create();
builder.setTitle("");
builder.setView(webViewPop);
builder.setButton("Close", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
webViewPop.destroy();
dialog.dismiss();
}
});
builder.show();
builder.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
transport.setWebView(webViewPop);
resultMsg.sendToTarget();
return true;
}
#Override
public void onCloseWindow(WebView window) {
//Toast.makeText(contextPop,"onCloseWindow called",Toast.LENGTH_SHORT).show();
try {
webViewPop.destroy();
} catch (Exception e) {
Log.d("Webview Destroy Error: ", e.getStackTrace().toString());
}
try {
builder.dismiss();
} catch (Exception e) {
Log.d("Builder Dismiss Error: ", e.getStackTrace().toString());
}
}
#Override
public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {
new AlertDialog.Builder(myApp)
.setMessage(message)
.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
result.confirm();
}
})
.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
result.cancel();
}
})
.setCancelable(false)
.create()
.show();
return true;
}
#Override
public boolean onJsAlert(WebView view, final String url, String message,
JsResult result) {
new AlertDialog.Builder(myApp)
.setMessage(message)
.setNeutralButton("OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface arg0, int arg1) {
arg0.dismiss();
}
})
.setCancelable(false)
.show();
result.cancel();
return true;
}
}
}
This is my very first post here, so please don't blame me if I'm not as complete and clear as I have to be.
The issue
I am new to React native and I recently began to develop a react native app which could read my incoming SMS's aloud. I already achieved to retrieve the incoming messages and to read them aloud... But only if the app is the foreground.
So, could you please advise me some libraries or tutorials on the subject ?
I'm working on a Nokia 5 with Android 9.
I currently use the following libraries :
React-native-android-sms-listener to retrieve the incoming messages.
React-native-tts to read the content aloud.
What I already tried
I'm searching the Internet for more than a week now (includig Stack Overflow and this example question) and I can't find what I'm looking for. I already tried React-native-background-timer and React-native-background-job. But I couldn't never get a background timer working and React-native-background-job allows tasks to be executed every 15 minutes only (due to the Android limitations).
So I read many articles like this one explaining how to use Headless JS and other libraries until I found this codeburst tutorial today, explaining how to develop a background service to record audio calls. I tried to adapt it, but the background service never starts.
My code
I must tell you that I don't have any knowledge in Java, so the native code below may contain mistakes, even if it is based on tutorials and the React native documentation.
Currently, when the app is launched, the service IncomingSMSService is called. This service, developed following the Codeburst tutorial referenced above, relies on Headless JS and a JS function that listen to the incoming messages and then read them aloud thanks to React-native-tts.
Here is these two files :
IncomingSMSService.java
package com.ava.service;
import android.content.Intent;
import android.os.Bundle;
import com.facebook.react.HeadlessJsTaskService;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.jstasks.HeadlessJsTaskConfig;
public class IncomingSMSService extends HeadlessJsTaskService {
#Override
protected HeadlessJsTaskConfig getTaskConfig(Intent intent) {
Bundle extras = intent.getExtras();
if (extras != null) {
return new HeadlessJsTaskConfig(
"HandleIncomingSMS",
Arguments.fromBundle(extras),
5000,
true
);
}
return null;
}
}
HandleIncomingSMS.js
import { AppRegistry } from 'react-native';
import SmsListener from 'react-native-android-sms-listener';
import Tts from 'react-native-tts';
const HandleIncomingSMS = async (taskData) => {
SmsListener.addListener(message => {
Tts.getInitStatus().then(() => {
Tts.speak(`New message from number ${message.originatingAddress} : ${message.body}`);
});
});
}
AppRegistry.registerHeadlessTask('HandleIncomingSMS', () => HandleIncomingSMS));
These pieces of code are called in a BroadcastReceiver here (IncomingSMSReceiver.java) :
package com.ava.receiver;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import com.ava.service.IncomingSMSService;
import com.facebook.react.HeadlessJsTaskService;
import java.util.List;
public final class IncomingSMSReceiver extends BroadcastReceiver {
#Override
public final void onReceive(Context context, Intent intent) {
if (!isAppOnForeground((context))) {
Intent service = new Intent(context, IncomingSMSService.class);
context.startService(service);
HeadlessJsTaskService.acquireWakeLockNow(context);
}
}
private boolean isAppOnForeground(Context context) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> appProcesses =
activityManager.getRunningAppProcesses();
if (appProcesses == null) {
return false;
}
final String packageName = context.getPackageName();
for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.importance ==
ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND &&
appProcess.processName.equals(packageName)) {
return true;
}
}
return false;
}
}
I also requested the good permissions in my AndroidManifest file, and I registered the service like so :
<service
android:name="com.ava.service.IncomingSMSService"
android:enabled="true"
android:label="IncomingSMSService"
/>
<receiver android:name="com.ava.receiver.IncomingSMSReceiver">
<intent-filter android:priority="0">
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
What am I doing wrong ? I don't even see service in the Running services tab of the Android Developer options... Any ideas ?
Thanks in advance for your help.
UPDATE (01/06/2019)
After reading or watching several tutorials like this one or this video, I managed to get my app working in the foreground. It now displays a persistent notification.
BUT, I don't know how I can "link" my service and my Broadcsat Receiver to this notification (for now, the service is called only if the app is in foreground).
Here is my updated code :
// IncomingSMSService
package com.ava.service;
import android.graphics.Color;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.ContextWrapper;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;
import com.facebook.react.HeadlessJsTaskService;
import com.ava.MainActivity;
import com.ava.R;
public class IncomingSMSService extends Service {
private NotificationManager notifManager;
private String CHANNEL_ID = "47";
private int SERVICE_NOTIFICATION_ID = 47;
private Handler handler = new Handler();
private Runnable runnableCode = new Runnable() {
#Override
public void run() {
Context context = getApplicationContext();
Intent myIntent = new Intent(context, IncomingSMSEventService.class);
context.startService(myIntent);
HeadlessJsTaskService.acquireWakeLockNow(context);
handler.postDelayed(this, 2000);
}
};
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
createNotificationChannel();
}
#Override
public void onDestroy() {
super.onDestroy();
}
public void createNotificationChannel() {
NotificationChannel notificationChannel = new NotificationChannel(CHANNEL_ID, "General", notifManager.IMPORTANCE_HIGH);
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.RED);
notificationChannel.setShowBadge(true);
notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
getManager().createNotificationChannel(notificationChannel);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
this.handler.post(this.runnableCode);
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Ava")
.setContentText("Listening for new messages...")
.setSmallIcon(R.mipmap.ic_launcher_round)
.setContentIntent(contentIntent)
.setOngoing(true)
.build();
startForeground(SERVICE_NOTIFICATION_ID, notification);
return START_NOT_STICKY;
}
private NotificationManager getManager() {
if (notifManager == null) {
notifManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
}
return notifManager;
}
}
My headlessJS task :
// HandleIncomingSMS.js
import SmsListener from 'react-native-android-sms-listener';
import Tts from 'react-native-tts';
import Contacts from 'react-native-contacts';
import { text } from 'react-native-communications';
module.exports = async () => {
// To lower other applications' sounds
Tts.setDucking(true);
// Prevent the TTS engine from repeating messages multiple times
Tts.addEventListener('tts-finish', (event) => Tts.stop());
SmsListener.addListener(message => {
Contacts.getAll((err, contacts) => {
if (err) throw err;
const contactsLoop = () => {
contacts.forEach((contact, index, contacts) => {
// Search only for mobile numbers
if (contact.phoneNumbers[0].label === 'mobile') {
// Format the contact number to be compared with the message.oritignatingAddress variable
let contactNumber = contact.phoneNumbers[0].number.replace(/^00/, '+');
contactNumber = contactNumber.replace(/[\s-]/g, '');
// Phone numbers comparison
if (contactNumber === message.originatingAddress) {
if (contact.familyName !== null) {
Tts.speak(`Nouveau message de ${contact.givenName} ${contact.familyName} : ${message.body}`);
} else {
// If the contact doesn't have a known family name, just say his first name
Tts.speak(`Nouveau message de ${contact.givenName} : ${message.body}`);
}
} else if (contactNumber !== message.originatingAddress && index === contacts.length) {
// If the number isn't recognized and if the contacts have been all checked, just say the phone number
Tts.speak(`Nouveau message du numéro ${message.originatingAddress} : ${message.body}`);
}
}
});
}
contactsLoop();
// Redirect to the SMS app
text(message.originatingAddress, message = false);
});
});
}
I also added the good permissions in my AndroidManifest.xml file like the following :
...
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
...
I made some progress but I am still stuck, so if you have any idea, please share them ! Thank you !
I'm trying to run a code in my android studio emulator but after I run it, the emulator keeps showing "(App name) has stopped. Open app again".
This is an app to get accelerometer and gyro sensor data from Android wear.
I've checked the logcat and found this error in the process.
03-06 04:18:57.364 3189-3189/com.drejkim.androidwearmotionsensors E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.drejkim.androidwearmotionsensors, PID: 3189
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.hardware.Sensor.getStringType()' on a null object reference
at com.drejkim.androidwearmotionsensors.SensorFragment.onCreateView(SensorFragment.java:63)
at android.app.Fragment.performCreateView(Fragment.java:2353)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:995)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1171)
at android.app.BackStackRecord.run(BackStackRecord.java:816)
at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1578)
at android.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:563)
at android.support.wearable.view.FragmentGridPagerAdapter.finishUpdate(FragmentGridPagerAdapter.java:196)
at android.support.wearable.view.GridViewPager.populate(GridViewPager.java:1161)
at android.support.wearable.view.GridViewPager.populate(GridViewPager.java:1008)
at android.support.wearable.view.GridViewPager.onMeasure(GridViewPager.java:1322)
at android.view.View.measure(View.java:19857)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6083)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
at android.view.View.measure(View.java:19857)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6083)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
at android.support.wearable.view.WatchViewStub.onMeasure(WatchViewStub.java:136)
at android.view.View.measure(View.java:19857)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6083)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
at android.view.View.measure(View.java:19857)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6083)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
at com.android.internal.policy.DecorView.onMeasure(DecorView.java:690)
at android.view.View.measure(View.java:19857)
at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2275)
at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1366)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1675)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1254)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6338)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:874)
at android.view.Choreographer.doCallbacks(Choreographer.java:686)
at android.view.Choreographer.doFrame(Choreographer.java:621)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:860)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
And here're three of my java codes:
SensorFragments.java:
package com.drejkim.androidwearmotionsensors;
import android.app.Fragment;
import android.content.Context;
import android.graphics.Color;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.util.FloatMath;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
public class SensorFragment extends Fragment implements SensorEventListener {
private static final float SHAKE_THRESHOLD = 1.1f;
private static final int SHAKE_WAIT_TIME_MS = 250;
private static final float ROTATION_THRESHOLD = 2.0f;
private static final int ROTATION_WAIT_TIME_MS = 100;
private View mView;
private TextView mTextTitle;
private TextView mTextValues;
private SensorManager mSensorManager;
private Sensor mSensor;
private int mSensorType;
private long mShakeTime = 0;
private long mRotationTime = 0;
public static SensorFragment newInstance(int sensorType) {
SensorFragment f = new SensorFragment();
// Supply sensorType as an argument
Bundle args = new Bundle();
args.putInt("sensorType", sensorType);
f.setArguments(args);
return f;
}
#Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle args = getArguments();
if(args != null) {
mSensorType = args.getInt("sensorType");
}
mSensorManager = (SensorManager) getActivity().getSystemService(Context.SENSOR_SERVICE);
mSensor = mSensorManager.getDefaultSensor(mSensorType);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mView = inflater.inflate(R.layout.sensor, container, false);
mTextTitle = (TextView) mView.findViewById(R.id.text_title);
mTextTitle.setText(mSensor.getStringType());
mTextValues = (TextView) mView.findViewById(R.id.text_values);
return mView;
}
#Override
public void onResume() {
super.onResume();
mSensorManager.registerListener(this, mSensor, SensorManager.SENSOR_DELAY_NORMAL);
}
#Override
public void onPause() {
super.onPause();
mSensorManager.unregisterListener(this);
}
#Override
public void onSensorChanged(SensorEvent event) {
// If sensor is unreliable, then just return
if (event.accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE)
{
return;
}
mTextValues.setText(
"x = " + Float.toString(event.values[0]) + "\n" +
"y = " + Float.toString(event.values[1]) + "\n" +
"z = " + Float.toString(event.values[2]) + "\n"
);
if(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
detectShake(event);
}
else if(event.sensor.getType() == Sensor.TYPE_GYROSCOPE) {
detectRotation(event);
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
// References:
// - http://jasonmcreynolds.com/?p=388
// - http://code.tutsplus.com/tutorials/using-the-accelerometer-on-android--mobile-22125
private void detectShake(SensorEvent event) {
long now = System.currentTimeMillis();
if((now - mShakeTime) > SHAKE_WAIT_TIME_MS) {
mShakeTime = now;
float gX = event.values[0] / SensorManager.GRAVITY_EARTH;
float gY = event.values[1] / SensorManager.GRAVITY_EARTH;
float gZ = event.values[2] / SensorManager.GRAVITY_EARTH;
// gForce will be close to 1 when there is no movement
float gForce = FloatMath.sqrt(gX*gX + gY*gY + gZ*gZ);
// Change background color if gForce exceeds threshold;
// otherwise, reset the color
if(gForce > SHAKE_THRESHOLD) {
mView.setBackgroundColor(Color.rgb(0, 100, 0));
}
else {
mView.setBackgroundColor(Color.BLACK);
}
}
}
private void detectRotation(SensorEvent event) {
long now = System.currentTimeMillis();
if((now - mRotationTime) > ROTATION_WAIT_TIME_MS) {
mRotationTime = now;
// Change background color if rate of rotation around any
// axis and in any direction exceeds threshold;
// otherwise, reset the color
if(Math.abs(event.values[0]) > ROTATION_THRESHOLD ||
Math.abs(event.values[1]) > ROTATION_THRESHOLD ||
Math.abs(event.values[2]) > ROTATION_THRESHOLD) {
mView.setBackgroundColor(Color.rgb(0, 100, 0));
}
else {
mView.setBackgroundColor(Color.BLACK);
}
}
}
}
MainActivity.Java:
package com.drejkim.androidwearmotionsensors;
import android.app.Activity;
import android.os.Bundle;
import android.support.wearable.view.DotsPageIndicator;
import android.support.wearable.view.GridViewPager;
import android.support.wearable.view.WatchViewStub;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub);
stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
#Override public void onLayoutInflated(WatchViewStub stub) {
final GridViewPager pager = (GridViewPager) findViewById(R.id.pager);
pager.setAdapter(new SensorFragmentPagerAdapter(getFragmentManager()));
DotsPageIndicator indicator = (DotsPageIndicator) findViewById(R.id.page_indicator);
indicator.setPager(pager);
}
});
}
}
SensorFragmentPagerAdapter.java:
package com.drejkim.androidwearmotionsensors;
import android.app.Fragment;
import android.app.FragmentManager;
import android.hardware.Sensor;
import android.support.wearable.view.FragmentGridPagerAdapter;
public class SensorFragmentPagerAdapter extends FragmentGridPagerAdapter {
private int[] sensorTypes = {
Sensor.TYPE_ACCELEROMETER,
Sensor.TYPE_GYROSCOPE
};
public SensorFragmentPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getFragment(int row, int column) {
return SensorFragment.newInstance(sensorTypes[column]);
}
#Override
public int getRowCount() {
return 1; // fix to 1 row
}
#Override
public int getColumnCount(int row) {
return sensorTypes.length;
}
}
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.drejkim.androidwearmotionsensors" >
<uses-feature android:name="android.hardware.type.watch" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#android:style/Theme.DeviceDefault" >
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Can someone help me out? I got this code from some source and I don't know how to fix it since the logcat is showing a long fatal exception script highlighted in red. Thank you, I'll really appreciate it if someone can help.
From the error message in LogCat you can read that mSensor is null when you try to execute
mTextTitle.setText(mSensor.getStringType());
This means that the your sensor manager is unable to find a default sensor that matches the requested type
mSensor = mSensorManager.getDefaultSensor(mSensorType);
as stated in the documentation.
I wrote a simple cordova plugin which displays an alert.
JS file: alert.js
module.exports = {
alert: function(title, message, buttonLabel, successCallback) {
cordova.exec(successCallback,
null, // No failure callback
"Alert",
"alert",
[title, message, buttonLabel]);
}
};
Java File: Alert.java
package com.acme.plugin.alert;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.DialogInterface;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.PluginResult;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class Alert extends CordovaPlugin {
protected void pluginInitialize() {
}
public boolean execute(String action, JSONArray args, CallbackContext callbackContext)
throws JSONException {
if (action.equals("alert")) {
alert(args.getString(0), args.getString(1), args.getString(2), callbackContext);
return true;
}
return false;
}
private synchronized void alert(final String title,
final String message,
final String buttonLabel,
final CallbackContext callbackContext) {
new AlertDialog.Builder(cordova.getActivity())
.setTitle(title)
.setMessage(message)
.setCancelable(false)
.setNeutralButton(buttonLabel, new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialogInterface, int which) {
dialogInterface.dismiss();
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 0));
}
})
.create()
.show();
}
}
How do I call the alert function of alert.js from another js? And what parameter should i pass to map to successCallback??
according to cordova git for creating plugin see github page you can do it like this
Add the following code to wherever you need to call the plugin functionality:
cordova.plugins.<PluginName>.<method>();
where <PluginName> is your plugin name and <method> is your method.
I'm trying to run a background service in Android using HeadlessJS API from react native. I've used the official docs to do it:
MainTask file:
package com.test.test;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.widget.Toast;
import com.facebook.react.HeadlessJsTaskService;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.jstasks.HeadlessJsTaskConfig;
public class MyTaskService extends HeadlessJsTaskService {
#Override
protected #Nullable HeadlessJsTaskConfig getTaskConfig(Intent intent) {
Bundle extras = intent.getExtras();
if (extras != null) {
return new HeadlessJsTaskConfig(
"SomeTaskName",
Arguments.fromBundle(extras),
5000);
}
return null;
}
}
I've also registered the task like this:
AppRegistry.registerHeadlessTask('SomeTaskName', () => 'SomeTaskName')
and SomeTaskName is a function that looks like this:
export async function SomeTaskName (taskData) {
alert('Esto es una tarea en background')
}
The way that I'm using to trigger this background task is using the startService method:
startService(new Intent(this, MyTaskService.class));
I tried startService in different parts of the android code but I can't see any alert or warning logs.
I'm trying to figure this out too. Here's what I've found so far.
If you don't put "extras" into to the Intent you pass to start the service then getTaskConfig() returns null.
protected #Nullable HeadlessJsTaskConfig getTaskConfig(Intent intent) {
Bundle extras = intent.getExtras();
if (extras != null) {
return new HeadlessJsTaskConfig(
"SomeTaskName",
Arguments.fromBundle(extras),
5000);
}
return null;
}
Either remove the check for extras != null, or add something like this before you call startService:
Intent myIntent = new Intent(this, MyTaskService.class);
myIntent.putExtras("isReady",true);
startService(myIntent);
Also, make sure you add the service to the manifest.
<application>
....
<service android:name=".MyTaskService" android:enabled="true" android:label="MyTaskService" />
</application>
You could change your getTaskConfig method to support an intent that has no extras:
#Override
protected #Nullable HeadlessJsTaskConfig getTaskConfig(Intent intent) {
Bundle extras = intent.getExtras();
WritableMap data = extras != null ? Arguments.fromBundle(extras) : null;
return new HeadlessJsTaskConfig(
"SomeTaskName",
data,
5000);
}
Your Application class needs to implement ReactApplication and return an initialized ReactNativeHost, eg:
private final ReactNativeHost reactNativeHost = new ReactNativeHost(this) {
#Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
#Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage()
);
}
};
#Override
public ReactNativeHost getReactNativeHost() {
return reactNativeHost;
}
You also have to add the service to your manifest, as A. Rob mentioned.
Edit
Instead of implementing ReactApplication (see above) it seems like you could also override protected ReactNativeHost getReactNativeHost() within the HeadlessJsTaskService.