i am completely new on java, and i am trying to implement a print test using Zebra SDK.
this Zebra SDK (at the end of the class there is a "getConfigLabel"), prints a constant "TEST", so i want to send a variable insted of constant. to get this, i understand that i have to send a parameter to the class, but it is not clear for me how to get this done.
thanks.
here is the class:
/***********************************************
* CONFIDENTIAL AND PROPRIETARY
*
* The source code and other information contained herein is the confidential and the exclusive property of
* ZIH Corp. and is subject to the terms and conditions in your end user license agreement.
* This source code, and any other information contained herein, shall not be copied, reproduced, published,
* displayed or distributed, in whole or in part, in any medium, by any means, for any purpose except as
* expressly permitted under such license agreement.
*
* Copyright ZIH Corp. 2012
*
* ALL RIGHTS RESERVED
***********************************************/
package com.zebra.android.devdemo.connectivity;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Looper;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.RadioGroup.OnCheckedChangeListener;
import android.widget.TextView;
import com.zebra.android.devdemo.R;
import com.zebra.sdk.comm.BluetoothConnection;
import com.zebra.sdk.comm.Connection;
import com.zebra.sdk.comm.ConnectionException;
import com.zebra.sdk.comm.TcpConnection;
import com.zebra.sdk.printer.PrinterLanguage;
import com.zebra.sdk.printer.ZebraPrinter;
import com.zebra.sdk.printer.ZebraPrinterFactory;
import com.zebra.sdk.printer.ZebraPrinterLanguageUnknownException;
public class ConnectivityDemo extends Activity {
private Connection printerConnection;
private RadioButton btRadioButton;
private ZebraPrinter printer;
private TextView statusField;
private EditText macAddress, ipDNSAddress, portNumber, vtextToPrint;
private Button testButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.connection_screen_with_status);
ipDNSAddress = (EditText) this.findViewById(R.id.ipAddressInput);
ipDNSAddress.setText(SettingsHelper.getIp(this));
vtextToPrint = (EditText) this.findViewById(R.id.textToPrint);
portNumber = (EditText) this.findViewById(R.id.portInput);
portNumber.setText(SettingsHelper.getPort(this));
macAddress = (EditText) this.findViewById(R.id.macInput);
macAddress.setText(SettingsHelper.getBluetoothAddress(this));
statusField = (TextView) this.findViewById(R.id.statusText);
btRadioButton = (RadioButton) this.findViewById(R.id.bluetoothRadio);
testButton = (Button) this.findViewById(R.id.testButton);
testButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
enableTestButton(false);
Looper.prepare();
doConnectionTest();
Looper.loop();
Looper.myLooper().quit();
}
}).start();
}
});
RadioGroup radioGroup = (RadioGroup) this.findViewById(R.id.radioGroup);
radioGroup.setOnCheckedChangeListener(new OnCheckedChangeListener() {
public void onCheckedChanged(RadioGroup group, int checkedId) {
if (checkedId == R.id.bluetoothRadio) {
toggleEditField(macAddress, true);
toggleEditField(portNumber, false);
toggleEditField(ipDNSAddress, false);
} else {
toggleEditField(portNumber, true);
toggleEditField(ipDNSAddress, true);
toggleEditField(macAddress, false);
}
}
});
}
private void toggleEditField(EditText editText, boolean set) {
/*
* Note: Disabled EditText fields may still get focus by some other means, and allow text input.
* See http://code.google.com/p/android/issues/detail?id=2771
*/
editText.setEnabled(set);
editText.setFocusable(set);
editText.setFocusableInTouchMode(set);
}
#Override
protected void onStop() {
super.onStop();
if (printerConnection != null && printerConnection.isConnected()) {
disconnect();
}
}
private void enableTestButton(final boolean enabled) {
runOnUiThread(new Runnable() {
public void run() {
testButton.setEnabled(enabled);
}
});
}
private boolean isBluetoothSelected() {
return btRadioButton.isChecked();
}
public ZebraPrinter connect() {
setStatus("Connecting...", Color.YELLOW);
printerConnection = null;
if (isBluetoothSelected()) {
printerConnection = new BluetoothConnection(getMacAddressFieldText());
SettingsHelper.saveBluetoothAddress(this, getMacAddressFieldText());
} else {
try {
int port = Integer.parseInt(getTcpPortNumber());
printerConnection = new TcpConnection(getTcpAddress(), port);
SettingsHelper.saveIp(this, getTcpAddress());
SettingsHelper.savePort(this, getTcpPortNumber());
} catch (NumberFormatException e) {
setStatus("Port Number Is Invalid", Color.RED);
return null;
}
}
try {
printerConnection.open();
setStatus("Connected", Color.GREEN);
} catch (ConnectionException e) {
setStatus("Comm Error! Disconnecting", Color.RED);
DemoSleeper.sleep(1000);
disconnect();
}
ZebraPrinter printer = null;
if (printerConnection.isConnected()) {
try {
printer = ZebraPrinterFactory.getInstance(printerConnection);
setStatus("Determining Printer Language", Color.YELLOW);
PrinterLanguage pl = printer.getPrinterControlLanguage();
setStatus("Printer Language " + pl, Color.BLUE);
} catch (ConnectionException e) {
setStatus("Unknown Printer Language", Color.RED);
printer = null;
DemoSleeper.sleep(1000);
disconnect();
} catch (ZebraPrinterLanguageUnknownException e) {
setStatus("Unknown Printer Language", Color.RED);
printer = null;
DemoSleeper.sleep(1000);
disconnect();
}
}
return printer;
}
public void disconnect() {
try {
setStatus("Disconnecting", Color.RED);
if (printerConnection != null) {
printerConnection.close();
}
setStatus("Not Connected", Color.RED);
} catch (ConnectionException e) {
setStatus("COMM Error! Disconnected", Color.RED);
} finally {
enableTestButton(true);
}
}
private void setStatus(final String statusMessage, final int color) {
runOnUiThread(new Runnable() {
public void run() {
statusField.setBackgroundColor(color);
statusField.setText(statusMessage);
}
});
DemoSleeper.sleep(200);
}
private String getMacAddressFieldText() {
return macAddress.getText().toString();
}
private String getTcpAddress() {
return ipDNSAddress.getText().toString();
}
private String getTcpPortNumber() {
return portNumber.getText().toString();
}
private void doConnectionTest() {
printer = connect();
if (printer != null) {
sendTestLabel();
} else {
disconnect();
}
}
private void sendTestLabel() {
try {
byte[] configLabel = getConfigLabel();
printerConnection.write(configLabel);
setStatus("Sending Data", Color.BLUE);
DemoSleeper.sleep(500);
if (printerConnection instanceof BluetoothConnection) {
String friendlyName = ((BluetoothConnection) printerConnection).getFriendlyName();
setStatus(friendlyName, Color.MAGENTA);
DemoSleeper.sleep(500);
}
} catch (ConnectionException e) {
setStatus(e.getMessage(), Color.RED);
} finally {
disconnect();
}
}
/*
* Returns the command for a test label depending on the printer control language
* The test label is a box with the word "TEST" inside of it
*
* _________________________
* | |
* | |
* | TEST |
* | |
* | |
* |_______________________|
*
*
*/
private byte[] getConfigLabel() {
PrinterLanguage printerLanguage = printer.getPrinterControlLanguage();
byte[] configLabel = null;
if (printerLanguage == PrinterLanguage.ZPL) {
configLabel = "^XA^FO17,16^GB379,371,8^FS^FT65,255^A0N,135,134^FDTEST^FS^XZ".getBytes();
} else if (printerLanguage == PrinterLanguage.CPCL) {
String cpclConfigLabel = "! 0 200 200 406 1\r\n" + "ON-FEED IGNORE\r\n" + "BOX 20 20 380 380 8\r\n" + "T 0 6 137 177 TEST\r\n" + "PRINT\r\n";
configLabel = cpclConfigLabel.getBytes();
}
return configLabel;
}
}
private byte[] getConfigLabel(String parameter) {
.....
String cpclConfigLabel = "! 0 200 200 406 1\r\n" + "ON-FEED IGNORE\r\n" + "BOX 20 20 380 380 8\r\n" + "T 0 6 137 177 " + parameter + "r\n" + "PRINT\r\n";
.......
}
This is how you take in an argument into a method.
When calling the method getConfigLabel, make sure you pass in the parameter String, if not it will causes error.
byte[] configLabel = getConfigLabel("Test");
At this line, which is 9 from the end:
configLabel = "^XA^FO17,16^GB379,371,8^FS^FT65,255^A0N,135,134^FDTEST^FS^XZ".getBytes();
you can replace TEST with your variable, e.g:
configLabel = "^XA^FO17,16^GB379,371,8^FS^FT65,255^A0N,135,134^FD" + text + "^FS^XZ".getBytes();
You also need to declare this variable somewhere in the getConfigLabel method or pass it to it.
I suggest changing method signature to getConfigLabel(String text) and modify line 9 from th end. In that case in methond sendTestLabel you can replace
byte[] configLabel = getConfigLabel();
with
String text = "some text...";
byte[] configLabel = getConfigLabel(text);
BTW, this is only the way to print something instead of "TEST". I suggest you use this only for understanding of how it works. If you want to further customize this code, you may need to add another methods, for fine printing
Related
I know that this questions was asked before but it doesn't solved by queries mentioned below after the code .
package io.agora.tutorials1v1vcall;
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import android.view.SurfaceView;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.Toast;
import io.agora.uikit.logger.LoggerRecyclerView;
import io.agora.rtc.IRtcEngineEventHandler;
import io.agora.rtc.RtcEngine;
import io.agora.rtc.video.VideoCanvas;
import io.agora.rtc.video.VideoEncoderConfiguration;
public class VideoChatViewActivity extends AppCompatActivity {
private static final String TAG = VideoChatViewActivity.class.getSimpleName();
private static final int PERMISSION_REQ_ID = 22;
// Permission WRITE_EXTERNAL_STORAGE is not mandatory
// for Agora RTC SDK, just in case if you wanna save
// logs to external sdcard.
private static final String[] REQUESTED_PERMISSIONS = {
Manifest.permission.RECORD_AUDIO,
Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
private RtcEngine mRtcEngine;
private boolean mCallEnd;
private boolean mMuted;
private FrameLayout mLocalContainer;
private RelativeLayout mRemoteContainer;
private SurfaceView mLocalView;
private SurfaceView mRemoteView;
private ImageView mCallBtn;
private ImageView mMuteBtn;
private ImageView mSwitchCameraBtn;
// Customized logger view
private LoggerRecyclerView mLogView;
/**
* Event handler registered into RTC engine for RTC callbacks.
* Note that UI operations needs to be in UI thread because RTC
* engine deals with the events in a separate thread.
*/
private final IRtcEngineEventHandler mRtcEventHandler = new IRtcEngineEventHandler() {
#Override
public void onJoinChannelSuccess(String channel, final int uid, int elapsed) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mLogView.logI("Join channel success, uid: " + (uid & 0xFFFFFFFFL));
}
});
}
#Override
public void onFirstRemoteVideoDecoded(final int uid, int width, int height, int elapsed) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mLogView.logI("First remote video decoded, uid: " + (uid & 0xFFFFFFFFL));
setupRemoteVideo(uid);
}
});
}
#Override
public void onUserOffline(final int uid, int reason) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mLogView.logI("User offline, uid: " + (uid & 0xFFFFFFFFL));
onRemoteUserLeft();
}
});
}
};
private void setupRemoteVideo(int uid) {
// Only one remote video view is available for this
// tutorial. Here we check if there exists a surface
// view tagged as this uid.
int count = mRemoteContainer.getChildCount();
View view = null;
for (int i = 0; i < count; i++) {
View v = mRemoteContainer.getChildAt(i);
if (v.getTag() instanceof Integer && ((int) v.getTag()) == uid) {
view = v;
}
}
if (view != null) {
return;
}
mRemoteView = RtcEngine.CreateRendererView(getBaseContext());
mRemoteContainer.addView(mRemoteView);
mRtcEngine.setupRemoteVideo(new VideoCanvas(mRemoteView, VideoCanvas.RENDER_MODE_HIDDEN, uid));
mRemoteView.setTag(uid);
}
private void onRemoteUserLeft() {
removeRemoteVideo();
}
private void removeRemoteVideo() {
if (mRemoteView != null) {
mRemoteContainer.removeView(mRemoteView);
}
mRemoteView = null;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_video_chat_view);
initUI();
// Ask for permissions at runtime.
// This is just an example set of permissions. Other permissions
// may be needed, and please refer to our online documents.
if (checkSelfPermission(REQUESTED_PERMISSIONS[0], PERMISSION_REQ_ID) &&
checkSelfPermission(REQUESTED_PERMISSIONS[1], PERMISSION_REQ_ID) &&
checkSelfPermission(REQUESTED_PERMISSIONS[2], PERMISSION_REQ_ID)) {
initEngineAndJoinChannel();
}
}
private void initUI() {
mLocalContainer = findViewById(R.id.local_video_view_container);
mRemoteContainer = findViewById(R.id.remote_video_view_container);
mCallBtn = findViewById(R.id.btn_call);
mMuteBtn = findViewById(R.id.btn_mute);
mSwitchCameraBtn = findViewById(R.id.btn_switch_camera);
mLogView = findViewById(R.id.log_recycler_view);
// Sample logs are optional.
showSampleLogs();
}
private void showSampleLogs() {
mLogView.logI("Welcome to Agora 1v1 video call");
mLogView.logW("You will see custom logs here");
mLogView.logE("You can also use this to show errors");
}
private boolean checkSelfPermission(String permission, int requestCode) {
if (ContextCompat.checkSelfPermission(this, permission) !=
PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, REQUESTED_PERMISSIONS, requestCode);
return false;
}
return true;
}
#Override
public void onRequestPermissionsResult(int requestCode,
#NonNull String[] permissions, #NonNull int[] grantResults) {
if (requestCode == PERMISSION_REQ_ID) {
if (grantResults[0] != PackageManager.PERMISSION_GRANTED ||
grantResults[1] != PackageManager.PERMISSION_GRANTED ||
grantResults[2] != PackageManager.PERMISSION_GRANTED) {
showLongToast("Need permissions " + Manifest.permission.RECORD_AUDIO +
"/" + Manifest.permission.CAMERA + "/" + Manifest.permission.WRITE_EXTERNAL_STORAGE);
finish();
return;
}
// Here we continue only if all permissions are granted.
// The permissions can also be granted in the system settings manually.
initEngineAndJoinChannel();
}
}
private void showLongToast(final String msg) {
this.runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();
}
});
}
private void initEngineAndJoinChannel() {
// This is our usual steps for joining
// a channel and starting a call.
initializeEngine();
setupVideoConfig();
setupLocalVideo();
joinChannel();
}
private void initializeEngine() {
try {
mRtcEngine = RtcEngine.create(getBaseContext(), getString(R.string.agora_app_id), mRtcEventHandler);
} catch (Exception e) {
Log.e(TAG, Log.getStackTraceString(e));
throw new RuntimeException("NEED TO check rtc sdk init fatal error\n" + Log.getStackTraceString(e));
}
}
private void setupVideoConfig() {
// In simple use cases, we only need to enable video capturing
// and rendering once at the initialization step.
// Note: audio recording and playing is enabled by default.
mRtcEngine.enableVideo();
// Please go to this page for detailed explanation
// https://docs.agora.io/en/Video/API%20Reference/java/classio_1_1agora_1_1rtc_1_1_rtc_engine.html#af5f4de754e2c1f493096641c5c5c1d8f
mRtcEngine.setVideoEncoderConfiguration(new VideoEncoderConfiguration(
VideoEncoderConfiguration.VD_640x360,
VideoEncoderConfiguration.FRAME_RATE.FRAME_RATE_FPS_15,
VideoEncoderConfiguration.STANDARD_BITRATE,
VideoEncoderConfiguration.ORIENTATION_MODE.ORIENTATION_MODE_FIXED_PORTRAIT));
}
private void setupLocalVideo() {
// This is used to set a local preview.
// The steps setting local and remote view are very similar.
// But note that if the local user do not have a uid or do
// not care what the uid is, he can set his uid as ZERO.
// Our server will assign one and return the uid via the event
// handler callback function (onJoinChannelSuccess) after
// joining the channel successfully.
mLocalView = RtcEngine.CreateRendererView(getBaseContext());
mLocalView.setZOrderMediaOverlay(true);
mLocalContainer.addView(mLocalView);
mRtcEngine.setupLocalVideo(new VideoCanvas(mLocalView, VideoCanvas.RENDER_MODE_HIDDEN, 0));
}
private void joinChannel() {
// 1. Users can only see each other after they join the
// same channel successfully using the same app id.
// 2. One token is only valid for the channel name that
// you use to generate this token.
String token = getString(R.string.agora_access_token);
if (TextUtils.isEmpty(token) || TextUtils.equals(token, "#YOUR ACCESS TOKEN#")) {
token = null; // default, no token
}
mRtcEngine.joinChannel(token, "demoChannel1", "Extra Optional Data", 0);
}
#Override
protected void onDestroy() {
super.onDestroy();
if (!mCallEnd) {
leaveChannel();
}
RtcEngine.destroy();
}
private void leaveChannel() {
mRtcEngine.leaveChannel();
}
public void onLocalAudioMuteClicked(View view) {
mMuted = !mMuted;
mRtcEngine.muteLocalAudioStream(mMuted);
int res = mMuted ? R.drawable.btn_mute : R.drawable.btn_unmute;
mMuteBtn.setImageResource(res);
}
public void onSwitchCameraClicked(View view) {
mRtcEngine.switchCamera();
}
public void onCallClicked(View view) {
if (mCallEnd) {
startCall();
mCallEnd = false;
mCallBtn.setImageResource(R.drawable.btn_endcall);
} else {
endCall();
mCallEnd = true;
mCallBtn.setImageResource(R.drawable.btn_startcall);
}
showButtons(!mCallEnd);
}
private void startCall() {
setupLocalVideo();
joinChannel();
}
private void endCall() {
removeLocalVideo();
removeRemoteVideo();
leaveChannel();
}
private void removeLocalVideo() {
if (mLocalView != null) {
mLocalContainer.removeView(mLocalView);
}
mLocalView = null;
}
private void showButtons(boolean show) {
int visibility = show ? View.VISIBLE : View.GONE;
mMuteBtn.setVisibility(visibility);
mSwitchCameraBtn.setVisibility(visibility);
}
}
I am integrating the agora.io for one-to-one video calling functionality. I got the above code from the agora.io documentation but i am getting the black remote screen . Also i would ask that how would i connect two users dynamically. What modifications i have to do in the above code for one-to-one video call functionality. Please help.Thanks in advance.
It showing black screen because of token issue. kindly check token generation code in backend. Most probably the reason for black screen is the token expiration time.
I have created a foreground service that gets user's geolocation after every 2 seconds the service than calculates the speed and performs some operation, the problem is application stops working after 24 hr and does not crash ( notification still in notification area remain ) and does not work in Oppo phones at all. Any help would be appreciated.
Thank you
Here is the code for my service
import android.app.KeyguardManager;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.graphics.PixelFormat;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.PowerManager;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationManagerCompat;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.Toast;
import org.json.JSONObject;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import java.io.File;
import java.io.FileWriter;
import java.util.Calendar;
import static java.lang.Math.acos;
import static java.lang.Math.cos;
import static java.lang.Math.sin;
public class drivingService extends Service implements LocationListener {
// Declaration of Initialized Variables
public static int PRIMARY_FOREGROUND_NOTIF_SERVICE_ID = 1001, //Declaration of integers
progress = 0;
public static boolean enabled = true, //Declaration of boolean flags
popupEnabled = false,
sent = false,
first = true,
locked = false,
removed = false,
popup_visible = false,
tmp_visible = false;
// Declaration of Uninitialized Variables
public static NotificationCompat.Builder notification;
private static String TAG = "LOCATION_THINGS"; //Declaration of strings
private static String id = "";
public int drive = 0,
stop = 0;
public double lat1, lat2, lng1, lng2;
public long time1, time2;
NotificationManager mNotificationManager;
NotificationManagerCompat cNotificationManager;
Database db;
WindowManager windowManager;
WindowManager.LayoutParams params;
private LocationManager mLocationManager = null; //Declaration of location manager
private ImageView popup, stopping;
boolean networkStatus;
//Returns true and false idf the device is locked or not
public static boolean isDeviceLocked(Context context) {
boolean isLocked = false;
// First we check the locked state
KeyguardManager keyguardManager = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
boolean inKeyguardRestrictedInputMode = keyguardManager.inKeyguardRestrictedInputMode();
if (inKeyguardRestrictedInputMode) {
isLocked = true;
} else {
// If password is not set in the settings, the inKeyguardRestrictedInputMode() returns false,
// so we need to check if screen on for this case
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
isLocked = !powerManager.isInteractive();
} else {
//noinspection deprecation
isLocked = !powerManager.isScreenOn();
}
}
return isLocked;
}
//Create notification for service
public void createSimpleNotification() {
String GROUP_KEY_WORK_EMAIL = "com.blitzapp.textriteDriverAlert.not";
notification = new NotificationCompat.Builder(getApplicationContext(), id)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.large))
.setSmallIcon(R.drawable.not)
.setContentTitle("TextRite")
.setContentText("TextRite - Drive Mode is Enabled")
.setGroup(GROUP_KEY_WORK_EMAIL)
.setOngoing(false)
.setOnlyAlertOnce(true);
}
//Runs service powered by notification
public void renderNotification() {
cNotificationManager = NotificationManagerCompat.from(this);
cNotificationManager.notify(PRIMARY_FOREGROUND_NOTIF_SERVICE_ID, notification.build());
startForeground(PRIMARY_FOREGROUND_NOTIF_SERVICE_ID, notification.build());
}
//Creates Notification Channel
public void createNotificationChannel() {
id = "_channel_01";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel mChannel = new NotificationChannel(id, "TextRite - Drive Mode is Enabled", importance);
mChannel.enableLights(true);
mNotificationManager.createNotificationChannel(mChannel);
}
}
private void addToLogs(double speed, boolean alert, boolean tmp, boolean netwrok) {
try {
File root = new File(getFilesDir(), "speed_logs");
Log.d("Address", "" + getFilesDir());
if (!root.exists()) {
root.mkdir();
}
File filepath = new File(root, "logs.txt");
if (!filepath.exists()) {
filepath.createNewFile();
}
FileWriter writer = new FileWriter(filepath, true);
writer.append("Time->" + Calendar.getInstance().getTime() + "==|| Speed->" + speed + " || Alert Visible->" + alert + " || Temp Visible->" + tmp +"Network Status"+networkStatus+" || DB Count"+Database.dbCount+"\n");
writer.flush();
writer.close();
} catch (Exception ex) {
Log.e("File_I/O", "" + ex);
}
}
//Runs only once when the service is created
#Override
public void onCreate() {
Log.e(TAG, "onCreate");
try {
createNotificationChannel();
createSimpleNotification();
renderNotification();
} catch (Exception ex) {
Toast.makeText(this, "" + ex, Toast.LENGTH_LONG).show();
}
}
//Event Emitter to stop service
private void sendEvent() {
MainApplication application = (MainApplication) this.getApplication();
ReactNativeHost reactNativeHost = application.getReactNativeHost();
ReactInstanceManager reactInstanceManager = reactNativeHost.getReactInstanceManager();
ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
if (reactContext != null) {
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("stopService", null);
}
}
//This function is not used through out the code it is just added because of parent class service
#Override
public IBinder onBind(Intent arg0) {
return null;
}
//Adds alert to db when screen is locked
public void addAlert() {
try {
boolean networkStatus = isNetworkAvailable();
String alert = new Alert().getJsonObject();
db.insertAlert(alert);
if (networkStatus == true) {
db.sendData();
}
} catch (Exception e) {
Toast.makeText(getApplicationContext(), "Some Error Occurred while sending alerts to server.", Toast.LENGTH_LONG).show();
}
}
//Runs every time the service is started
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
try {
//Initialize database
db = new Database(getApplicationContext());
// Check If Force Stop button is presses
if (intent.getAction() != null && intent.getAction().equals("STOP")) {
stopForeground(true);
onDestroy();
} else {
// Check if switch is enabled then register location listener and create popup to render later
if (enabled) {
try {
getLocation();
createPopup();
//If any kind of mishap occurs report the user via toast message
} catch (Exception e) {
Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
}
// if switch not open by user then stop service
} else {
stopForeground(true);
onDestroy();
}
}
//If any kind of mishap occurs report the user via toast message
} catch (Exception ex) {
Toast.makeText(this, "Some Error Occurred while starting the service.", Toast.LENGTH_LONG).show();
}
return START_NOT_STICKY;
}
//Start the listener
private void getLocation() {
initializeLocationManager();
try {
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 0, this);
} catch (SecurityException ex) {
Toast.makeText(this, "Failed to request location update", Toast.LENGTH_LONG).show();
} catch (IllegalArgumentException ex) {
Toast.makeText(this, "GPS provider does not exist ", Toast.LENGTH_LONG).show();
}
}
//Take true or false in argument to render popup
public void clearAll() {
showTemp(false);
removed = true;
popupEnabled = false;
}
public void showPopup(boolean show) {
if (show == true) {
try {
stopping.setVisibility(View.INVISIBLE);
} catch (Exception e) {
}
popup.setVisibility(View.VISIBLE);
popup_visible = true;
popupEnabled = true;
} else {
popup.setVisibility(View.INVISIBLE);
popup_visible = false;
}
}
public void showTemp(boolean show) {
if (show == true) {
try {
popup.setVisibility(View.INVISIBLE);
} catch (Exception e) {
}
popupEnabled = true;
stopping.setVisibility(View.VISIBLE);
tmp_visible = true;
} else {
stopping.setVisibility(View.INVISIBLE);
tmp_visible = false;
}
}
//Creates popup or the alert window
private void createPopup() {
int LAYOUT_TYPE;
//Layout Parameters Declared
params = new WindowManager.LayoutParams();
//Setting Layout type According to build version of phone
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
LAYOUT_TYPE = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
LAYOUT_TYPE = WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
}
//Setting Up Layout Type and other properties
params.width = WindowManager.LayoutParams.MATCH_PARENT;
params.height = WindowManager.LayoutParams.MATCH_PARENT;
params.type = LAYOUT_TYPE;
params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS |
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
params.format = PixelFormat.TRANSLUCENT;
params.gravity = Gravity.CENTER;
params.x = 0;
params.y = 0;
//Check if Service is enabled by user then create popup set its visibility to false for later use
try {
if (enabled) {
//Window Manager Initialized
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
//Setting properties and parameters of popup to be viewed
popup = new ImageView(this);
popup.setImageResource(R.drawable.alert_potrait);
popup.setScaleType(ImageView.ScaleType.FIT_XY);
stopping = new ImageView(this);
stopping.setImageResource(R.drawable.stopping);
stopping.setScaleType(ImageView.ScaleType.FIT_XY);
windowManager.addView(popup, params);
windowManager.addView(stopping, params);
popup.setVisibility(View.INVISIBLE);
stopping.setVisibility(View.INVISIBLE);
}
//If any kind of mishap occurs report the user via toast message
} catch (Exception ex) {
Toast.makeText(this, "Some Error Occurred while creating Overlay Screen", Toast.LENGTH_LONG).show();
}
}
//Runs when is stopped
#Override
public void onDestroy() {
super.onDestroy();
try {
//set enabled service by user to false
enabled = false;
//disable popup visibility
popup.setVisibility(View.INVISIBLE);
//Unregister location manager for updates if it's not null
if (mLocationManager != null) {
mLocationManager.removeUpdates(this);
}
//send Event to React Native that service has stopped
sendEvent();
stopSelf();
} catch (Exception ex) {
Toast.makeText(getApplicationContext(), "Some Error Occurred, Restart your phone to avoid any inconvenience", Toast.LENGTH_LONG).show();
}
}
//Location Manager Initialization to access location listener
private void initializeLocationManager() {
if (mLocationManager == null) {
mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
}
}
//Returns true and false is network is connected or not
private boolean isNetworkAvailable() {
ConnectivityManager connectivityManager
= (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}
//Runs Every 2 second and returns the current location of the device
#Override
public void onLocationChanged(Location location) {
// check if location is not null or value is not a garbage value
if (location != null) {
//setting up variables to calculate speed
lat2 = lat1;
lng2 = lng1;
time2 = time1;
lat1 = location.getLatitude();
lng1 = location.getLongitude();
time1 = location.getTime();
//calculations performed
double distance = getDistance(lat1, lng1, lat2, lng2);
double time = calcTime(time1, time2);
double speed = distance / time;
Log.d("error: ",location.toString());
try {
networkStatus = isNetworkAvailable();
if (networkStatus == true) {
JSONObject log;
log = new JSONObject();
log.put("type","location_inside_if");
log.put("location_object",location.toString());
log.put("latitude",location.getLatitude());
log.put("longitude",location.getLongitude());
log.put("get_speed",speed);
log.put("speed_calculated",location.getSpeed());
log.put("drive",drive);
log.put("stop",stop);
log.put("locked",locked);
Log.d("Location_object", log.toString());
db.sendLogsData(log);
db.sendData();
}
} catch (Exception e) {
}
//if speed is greater than 8
if (speed >= 8) {
drive++;
stop = 0;
if (locked == true) {
locked = false;
showPopup(true);
} else {
if (drive == 5) {
showPopup(true);
drive = 0;
}
}
}
// if speed in less than 8
else {
drive = 0;
stop++;
popup.setVisibility(View.INVISIBLE);
if (locked == true) {
//Log.d("Log_Lock", "JUST AFTER UNLOCK: locked = true");
locked = false;
if (stop >= 25 && tmp_visible == true) {
if (tmp_visible) {
//Log.d("Log_Lock", "JUST AFTER UNLOCK: temp time up / back to normal");
clearAll();
stop = 0;
}
} else if (stop == 0) {
if (popup_visible) {
showTemp(true);
Log.d("Log_Lock", "JUST AFTER UNLOCK: timer running");
}
}
} else {
//Log.d("Log_Lock", "JUST AFTER UNLOCK: locked = false " + popupEnabled + " " + popup_visible + " " + tmp_visible);
if (popup_visible) {
//Log.d("Log_Lock", "AFTER SOMETIME: show temp popup");
showPopup(false);
showTemp(true);
drive = 0;
} else if (tmp_visible) {
showTemp(true);
if (stop >= 25) {
//Log.d("Log_Lock", "AFTER SOMETIME: temp time up");
clearAll();
stop = 0;
}
}
else{
clearAll();
}
}
}
if (isDeviceLocked(getApplicationContext())) {
popup.setVisibility(View.INVISIBLE);
stopping.setVisibility(View.INVISIBLE);
locked = true;
if (sent == false) {
addAlert();
sent = true;
}
} else {
sent = false;
}
}else{
try {
networkStatus = isNetworkAvailable();
if (networkStatus == true) {
JSONObject log;
log = new JSONObject();
log.put("type","inside_location_null");
log.put("location_object",location.toString());
log.put("drive",drive);
log.put("stop",stop);
log.put("locked",locked);
db.sendLogsData(log);
db.sendData();
}
} catch (Exception e) {
}
}
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
try {
networkStatus = isNetworkAvailable();
if (networkStatus == true) {
JSONObject log;
log = new JSONObject();
log.put("type","onStatusChanged");
log.put("provider",provider);
log.put("status",status);
log.put("extras",extras);
log.put("drive",drive);
log.put("stop",stop);
log.put("locked",locked);
db.sendLogsData(log);
}
} catch (Exception e) {
}
}
#Override
public void onProviderEnabled(String provider) {
try {
networkStatus = isNetworkAvailable();
if (networkStatus == true) {
JSONObject log;
log = new JSONObject();
log.put("type","onProviderEnabled");
log.put("provider",provider);
log.put("drive",drive);
log.put("stop",stop);
log.put("locked",locked);
db.sendLogsData(log);
}
} catch (Exception e) {
}
}
#Override
public void onProviderDisabled(String provider) {
try {
networkStatus = isNetworkAvailable();
if (networkStatus == true) {
JSONObject log;
log = new JSONObject();
log.put("type","onProviderDisabled");
log.put("provider",provider);
log.put("drive",drive);
log.put("stop",stop);
log.put("locked",locked);
db.sendLogsData(log);
}
} catch (Exception e) {
}
}
//Returns the distance between two locations
double getDistance(double lat1, double lon1, double lat2, double lon2) {
double M_PI = Math.PI;
// Convert degrees to radians
lat1 = lat1 * M_PI / 180.0;
lon1 = lon1 * M_PI / 180.0;
lat2 = lat2 * M_PI / 180.0;
lon2 = lon2 * M_PI / 180.0;
// radius of earth in metres
double r = 6378100;
// P
double rho1 = r * cos(lat1);
double z1 = r * sin(lat1);
double x1 = rho1 * cos(lon1);
double y1 = rho1 * sin(lon1);
// Q
double rho2 = r * cos(lat2);
double z2 = r * sin(lat2);
double x2 = rho2 * cos(lon2);
double y2 = rho2 * sin(lon2);
// Dot product
double dot = (x1 * x2 + y1 * y2 + z1 * z2);
double cos_theta = dot / (r * r);
double theta = acos(cos_theta);
// Distance in Metres
Log.d("Dist DISTANCE", Double.toString(r * theta));
return r * theta;
}
//Returns time in milliseconds between two locations
private double calcTime(double t1, double t2) {
Log.d("DIS_DIFF", Double.toString((t1 - t2) / 1000));
return (t1 - t2) / 1000;
}
}
what I want to do is developing an app that reads health data that collected by Samsung watch so I tried to use Samsung android health SDK . Moreover reading steps was very easy as there was a sample app doing the same thing . the issue appear when I was trying to read the heart rate value :
here is my code please help me address the issue :
Mainfest :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.smaunghealth">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<meta-data android:name="com.samsung.android.health.permission.read"
android:value="com.samsung.health.step_count;com.samsung.health.heart_rate"/>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
MainActivity
package com.example.smaunghealth;
import android.content.DialogInterface;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import com.samsung.android.sdk.healthdata.*;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class MainActivity extends AppCompatActivity {
public static final String APP_TAG = "SimpleHealth";
private static MainActivity mInstance = null;
private HealthDataStore mStore;
private HealthConnectionErrorResult mConnError;
private Set<HealthPermissionManager.PermissionKey> mKeySet;
private StepCountReporter mReporter;
private HeartRateReporter mHeartReporter;
TextView stepCount ;
TextView heartRate ;
private final HealthResultHolder.ResultListener<HealthPermissionManager.PermissionResult> mPermissionListener =
new HealthResultHolder.ResultListener<HealthPermissionManager.PermissionResult>() {
#Override
public void onResult(HealthPermissionManager.PermissionResult result) {
Log.d(APP_TAG, "Permission callback is received.");
Map<HealthPermissionManager.PermissionKey, Boolean> resultMap = result.getResultMap();
if (resultMap.containsValue(Boolean.FALSE)) {
// Requesting permission fails
} else {
// Get the current step count and display it
}
}
};
private final HealthDataStore.ConnectionListener mConnectionListener = new HealthDataStore.ConnectionListener() {
#Override
public void onConnected() {
Log.d(APP_TAG, "Health data service is connected.");
HealthPermissionManager pmsManager = new HealthPermissionManager(mStore);
try {
// Check whether the permissions that this application needs are acquired
Map<HealthPermissionManager.PermissionKey, Boolean> resultMap = pmsManager.isPermissionAcquired(mKeySet);
if (resultMap.containsValue(Boolean.FALSE)) {
// Request the permission for reading step counts if it is not acquired
pmsManager.requestPermissions(mKeySet, MainActivity.this).setResultListener(mPermissionListener);
} else {
// Get the current step count and display it
// ...
mReporter = new StepCountReporter(mStore);
mReporter.start(mStepCountObserver);
mHeartReporter = new HeartRateReporter(mStore);
mHeartReporter.start(heartRateObserver);
}
} catch (Exception e) {
Log.e(APP_TAG, e.getClass().getName() + " - " + e.getMessage());
Log.e(APP_TAG, "Permission setting fails.");
}
}
#Override
public void onConnectionFailed(HealthConnectionErrorResult error) {
Log.d(APP_TAG, "Health data service is not available.");
showConnectionFailureDialog(error);
}
#Override
public void onDisconnected() {
Log.d(APP_TAG, "Health data service is disconnected.");
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mInstance = this;
stepCount= (TextView) findViewById(R.id.step_count);
heartRate= (TextView) findViewById(R.id.heart_rate);
mKeySet = new HashSet<HealthPermissionManager.PermissionKey>();
// mKeySet.add(new HealthPermissionManager.PermissionKey(HealthConstants.StepCount.HEALTH_DATA_TYPE, HealthPermissionManager.PermissionType.READ));
mKeySet.add(new HealthPermissionManager.PermissionKey(HealthConstants.HeartRate.HEART_RATE, HealthPermissionManager.PermissionType.READ));
HealthDataService healthDataService = new HealthDataService();
try {
healthDataService.initialize(this);
} catch (Exception e) {
e.printStackTrace();}
mStore = new HealthDataStore(this, mConnectionListener);
// Request the connection to the health data store
mStore.connectService();
}
#Override
public void onDestroy() {
mStore.disconnectService();
super.onDestroy();
}
private StepCountReporter.StepCountObserver mStepCountObserver = count -> {
Log.d(APP_TAG, "Step reported : " + count);
updateStepCountView(String.valueOf(count));
};
private HeartRateReporter.HeartRateObserver heartRateObserver = count -> {
Log.d(APP_TAG, "Step reported : " + count);
updateHeartRateView(String.valueOf(count));
};
private void updateHeartRateView(String valueOf) {
Log.d(APP_TAG, "heart rate reported : " + valueOf);
updateHeartRateView(String.valueOf(valueOf));
}
private void updateStepCountView(String count) {
stepCount.setText(count);
}
private void showConnectionFailureDialog(HealthConnectionErrorResult error) {
AlertDialog.Builder alert = new AlertDialog.Builder(this);
mConnError = error;
String message = "Connection with Samsung Health is not available";
if (mConnError.hasResolution()) {
switch(error.getErrorCode()) {
case HealthConnectionErrorResult.PLATFORM_NOT_INSTALLED:
message = "Please install Samsung Health";
break;
case HealthConnectionErrorResult.OLD_VERSION_PLATFORM:
message = "Please upgrade Samsung Health";
break;
case HealthConnectionErrorResult.PLATFORM_DISABLED:
message = "Please enable Samsung Health";
break;
case HealthConnectionErrorResult.USER_AGREEMENT_NEEDED:
message = "Please agree with Samsung Health policy";
break;
default:
message = "Please make Samsung Health available";
break;
}
}
alert.setMessage(message);
alert.setPositiveButton("OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
if (mConnError.hasResolution()) {
mConnError.resolve(mInstance);
}
}
});
if (error.hasResolution()) {
alert.setNegativeButton("Cancel", null);
}
alert.show();
}
}
HeartRateReporter
package com.example.smaunghealth;
import android.util.Log;
import com.samsung.android.sdk.healthdata.*;
import java.util.Calendar;
import java.util.TimeZone;
public class HeartRateReporter {
private final HealthDataStore mStore;
private HeartRateObserver mHeartRateObserver;
private static final long ONE_DAY_IN_MILLIS = 24 * 60 * 60 * 1000L;
public HeartRateReporter(HealthDataStore store) {
mStore = store;
}
public void start(HeartRateObserver listener) {
mHeartRateObserver = listener;
HealthDataObserver.addObserver(mStore, HealthConstants.HeartRate.HEART_RATE, mObserver);
readHeartRate();
}
private void readHeartRate() {
HealthDataResolver resolver = new HealthDataResolver(mStore, null);
// Set time range from start time of today to the current time
long startTime = getStartTimeOfToday();
long endTime = startTime + ONE_DAY_IN_MILLIS;
HealthDataResolver.ReadRequest request = new HealthDataResolver.ReadRequest.Builder()
.setDataType(HealthConstants.HeartRate.HEART_RATE)
.setProperties(new String[] {HealthConstants.HeartRate.HEART_RATE})
.setLocalTimeRange(HealthConstants.HeartRate.START_TIME, HealthConstants.HeartRate.TIME_OFFSET,
startTime, endTime)
.build();
try {
resolver.read(request).setResultListener(mListener);
} catch (Exception e) {
Log.e("*&*&*&", "Getting Heart fails.", e);
}
}
private long getStartTimeOfToday() {
Calendar today = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
today.set(Calendar.HOUR_OF_DAY, 0);
today.set(Calendar.MINUTE, 0);
today.set(Calendar.SECOND, 0);
today.set(Calendar.MILLISECOND, 0);
return today.getTimeInMillis();
}
private final HealthResultHolder.ResultListener<HealthDataResolver.ReadResult> mListener = result -> {
int count = 0;
try {
for (HealthData data : result) {
count += data.getInt(HealthConstants.HeartRate.HEART_RATE);
}
} finally {
result.close();
}
if (mHeartRateObserver != null) {
mHeartRateObserver.onChanged(count);
}
};
private final HealthDataObserver mObserver = new HealthDataObserver(null) {
#Override
public void onChange(String dataTypeName) {
Log.d("*&*&*&", "Observer receives a data changed event");
readHeartRate();
}
};
public interface HeartRateObserver {
void onChanged(int count);
}
}
StepCountReporter
/**
* Copyright (C) 2014 Samsung Electronics Co., Ltd. All rights reserved.
*
* Mobile Communication Division,
* Digital Media & Communications Business, Samsung Electronics Co., Ltd.
*
* This software and its documentation are confidential and proprietary
* information of Samsung Electronics Co., Ltd. No part of the software and
* documents may be copied, reproduced, transmitted, translated, or reduced to
* any electronic medium or machine-readable form without the prior written
* consent of Samsung Electronics.
*
* Samsung Electronics makes no representations with respect to the contents,
* and assumes no responsibility for any errors that might appear in the
* software and documents. This publication and the contents hereof are subject
* to change without notice.
*/
package com.example.smaunghealth;
import android.util.Log;
import com.samsung.android.sdk.healthdata.*;
import com.samsung.android.sdk.healthdata.HealthDataResolver.ReadRequest;
import com.samsung.android.sdk.healthdata.HealthDataResolver.ReadResult;
import java.util.Calendar;
import java.util.TimeZone;
public class StepCountReporter {
private final HealthDataStore mStore;
private StepCountObserver mStepCountObserver;
private static final long ONE_DAY_IN_MILLIS = 24 * 60 * 60 * 1000L;
public StepCountReporter(HealthDataStore store) {
mStore = store;
}
public void start(StepCountObserver listener) {
mStepCountObserver = listener;
// Register an observer to listen changes of step count and get today step count
HealthDataObserver.addObserver(mStore, HealthConstants.StepCount.HEALTH_DATA_TYPE, mObserver);
readTodayStepCount();
}
// Read the today's step count on demand
private void readTodayStepCount() {
HealthDataResolver resolver = new HealthDataResolver(mStore, null);
// Set time range from start time of today to the current time
long startTime = getStartTimeOfToday();
long endTime = startTime + ONE_DAY_IN_MILLIS;
HealthDataResolver.ReadRequest request = new ReadRequest.Builder()
.setDataType(HealthConstants.StepCount.HEALTH_DATA_TYPE)
.setProperties(new String[] {HealthConstants.StepCount.COUNT})
.setLocalTimeRange(HealthConstants.StepCount.START_TIME, HealthConstants.StepCount.TIME_OFFSET,
startTime, endTime)
.build();
try {
resolver.read(request).setResultListener(mListener);
} catch (Exception e) {
Log.e(MainActivity.APP_TAG, "Getting step count fails.", e);
}
}
private long getStartTimeOfToday() {
Calendar today = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
today.set(Calendar.HOUR_OF_DAY, 0);
today.set(Calendar.MINUTE, 0);
today.set(Calendar.SECOND, 0);
today.set(Calendar.MILLISECOND, 0);
return today.getTimeInMillis();
}
private final HealthResultHolder.ResultListener<ReadResult> mListener = result -> {
int count = 0;
try {
for (HealthData data : result) {
count += data.getInt(HealthConstants.StepCount.COUNT);
}
} finally {
result.close();
}
if (mStepCountObserver != null) {
mStepCountObserver.onChanged(count);
}
};
private final HealthDataObserver mObserver = new HealthDataObserver(null) {
// Update the step count when a change event is received
#Override
public void onChange(String dataTypeName) {
Log.d(MainActivity.APP_TAG, "Observer receives a data changed event");
readTodayStepCount();
}
};
public interface StepCountObserver {
void onChanged(int count);
}
}
Here is the exception log :
<meta-data android:name="com.samsung.android.health.permission.read"
android:value="com.samsung.health.step_count;com.samsung.health.heart_rate"/>
I think you should separate this permission into two, not only one。
like:
<meta-data android:name="com.samsung.android.health.permission.read"
android:value="com.samsung.health.step_count"/>
<meta-data android:name="com.samsung.android.health.permission.read"
android:value="com.samsung.health.heart_rate"/>
After long time finally I was able to address the issue :
mKeySet.add(new HealthPermissionManager.PermissionKey(HealthConstants.StepCount.HEALTH_DATA_TYPE, HealthPermissionManager.PermissionType.READ));
mKeySet.add(new HealthPermissionManager.PermissionKey(HealthConstants.HeartRate.HEART_RATE, HealthPermissionManager.PermissionType.READ));
this is the write permissionKey :
mKeySet.add(new HealthPermissionManager.PermissionKey(HealthConstants.StepCount.HEALTH_DATA_TYPE, HealthPermissionManager.PermissionType.READ));
mKeySet.add(new HealthPermissionManager.PermissionKey(HealthConstants.HeartRate.HEALTH_DATA_TYPE, HealthPermissionManager.PermissionType.READ));
It appears that the whole inmobi sdk has changed significantly from 4.4.1 to 5.2.3 which means that I cannot integrate the inmobi sdk successfully into mopub. This is adapter bundled within the mopub sdk:
https://github.com/motain/android-ads-MoPub/blob/master/extras/src/com/mopub/nativeads/InMobiNative.java
I have copied and pasted the code here for your convenience - you can see that the author has said that the adapter was tested on 4.4.1:
package com.mopub.nativeads;
import android.app.Activity;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import com.inmobi.commons.InMobi;
import com.inmobi.monetization.IMErrorCode;
import com.inmobi.monetization.IMNative;
import com.inmobi.monetization.IMNativeListener;
import com.mopub.common.util.MoPubLog;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static com.mopub.common.util.Json.getJsonValue;
import static com.mopub.common.util.Numbers.parseDouble;
/*
* Tested with InMobi SDK 4.4.1
*/
class InMobiNative extends CustomEventNative implements IMNativeListener {
private static final String APP_ID_KEY = "app_id";
private Context mContext;
private CustomEventNativeListener mCustomEventNativeListener;
// CustomEventNative implementation
#Override
protected void loadNativeAd(final Context context,
final CustomEventNativeListener customEventNativeListener,
final Map<String, Object> localExtras,
final Map<String, String> serverExtras) {
mContext = context;
if (!(context instanceof Activity)) {
customEventNativeListener.onNativeAdFailed(NativeErrorCode.NATIVE_ADAPTER_CONFIGURATION_ERROR);
return;
}
final Activity activity = (Activity) context;
final String appId;
if (extrasAreValid(serverExtras)) {
appId = serverExtras.get(APP_ID_KEY);
} else {
customEventNativeListener.onNativeAdFailed(NativeErrorCode.NATIVE_ADAPTER_CONFIGURATION_ERROR);
return;
}
mCustomEventNativeListener = customEventNativeListener;
InMobi.initialize(activity, appId);
final IMNative imNative = new IMNative(this);
imNative.loadAd();
}
// IMNativeListener implementation
#Override
public void onNativeRequestSucceeded(final IMNative imNative) {
if (imNative == null) {
mCustomEventNativeListener.onNativeAdFailed(NativeErrorCode.NETWORK_INVALID_STATE);
return;
}
final InMobiForwardingNativeAd inMobiForwardingNativeAd;
try {
inMobiForwardingNativeAd = new InMobiForwardingNativeAd(imNative);
} catch (IllegalArgumentException e) {
mCustomEventNativeListener.onNativeAdFailed(NativeErrorCode.UNSPECIFIED);
return;
} catch (JSONException e) {
mCustomEventNativeListener.onNativeAdFailed(NativeErrorCode.INVALID_JSON);
return;
}
final List<String> imageUrls = new ArrayList<String>();
final String mainImageUrl = inMobiForwardingNativeAd.getMainImageUrl();
if (mainImageUrl != null) {
imageUrls.add(mainImageUrl);
}
final String iconUrl = inMobiForwardingNativeAd.getIconImageUrl();
if (iconUrl != null) {
imageUrls.add(iconUrl);
}
preCacheImages(mContext, imageUrls, new ImageListener() {
#Override
public void onImagesCached() {
mCustomEventNativeListener.onNativeAdLoaded(inMobiForwardingNativeAd);
}
#Override
public void onImagesFailedToCache(NativeErrorCode errorCode) {
mCustomEventNativeListener.onNativeAdFailed(errorCode);
}
});
}
#Override
public void onNativeRequestFailed(final IMErrorCode errorCode) {
if (errorCode == IMErrorCode.INVALID_REQUEST) {
mCustomEventNativeListener.onNativeAdFailed(NativeErrorCode.NETWORK_INVALID_REQUEST);
} else if (errorCode == IMErrorCode.INTERNAL_ERROR || errorCode == IMErrorCode.NETWORK_ERROR) {
mCustomEventNativeListener.onNativeAdFailed(NativeErrorCode.NETWORK_INVALID_STATE);
} else if (errorCode == IMErrorCode.NO_FILL) {
mCustomEventNativeListener.onNativeAdFailed(NativeErrorCode.NETWORK_NO_FILL);
} else {
mCustomEventNativeListener.onNativeAdFailed(NativeErrorCode.UNSPECIFIED);
}
}
private boolean extrasAreValid(final Map<String, String> serverExtras) {
final String placementId = serverExtras.get(APP_ID_KEY);
return (placementId != null && placementId.length() > 0);
}
static class InMobiForwardingNativeAd extends BaseForwardingNativeAd {
static final int IMPRESSION_MIN_TIME_VIEWED = 0;
// Modifiable keys
static final String TITLE = "title";
static final String DESCRIPTION = "description";
static final String SCREENSHOTS = "screenshots";
static final String ICON = "icon";
static final String LANDING_URL = "landing_url";
static final String CTA = "cta";
static final String RATING = "rating";
// Constant keys
static final String URL = "url";
private final IMNative mImNative;
InMobiForwardingNativeAd(final IMNative imNative) throws IllegalArgumentException, JSONException {
if (imNative == null) {
throw new IllegalArgumentException("InMobi Native Ad cannot be null");
}
mImNative = imNative;
final JSONTokener jsonTokener = new JSONTokener(mImNative.getContent());
final JSONObject jsonObject = new JSONObject(jsonTokener);
setTitle(getJsonValue(jsonObject, TITLE, String.class));
setText(getJsonValue(jsonObject, DESCRIPTION, String.class));
final JSONObject screenShotJsonObject = getJsonValue(jsonObject, SCREENSHOTS, JSONObject.class);
if (screenShotJsonObject != null) {
setMainImageUrl(getJsonValue(screenShotJsonObject, URL, String.class));
}
final JSONObject iconJsonObject = getJsonValue(jsonObject, ICON, JSONObject.class);
if (iconJsonObject != null) {
setIconImageUrl(getJsonValue(iconJsonObject, URL, String.class));
}
setClickDestinationUrl(getJsonValue(jsonObject, LANDING_URL, String.class));
setCallToAction(getJsonValue(jsonObject, CTA, String.class));
try {
setStarRating(parseDouble(jsonObject.opt(RATING)));
} catch (ClassCastException e) {
MoPubLog.d("Unable to set invalid star rating for InMobi Native.");
}
setImpressionMinTimeViewed(IMPRESSION_MIN_TIME_VIEWED);
}
#Override
public void prepareImpression(final View view) {
if (view != null && view instanceof ViewGroup) {
mImNative.attachToView((ViewGroup) view);
} else if (view != null && view.getParent() instanceof ViewGroup) {
mImNative.attachToView((ViewGroup) view.getParent());
} else {
MoPubLog.e("InMobi did not receive ViewGroup to attachToView, unable to record impressions");
}
}
#Override
public void handleClick(final View view) {
mImNative.handleClick(null);
}
#Override
public void destroy() {
mImNative.detachFromView();
}
}
}
Has anyone been successful in converting this adapter to work with the latest 5.2.3 inmobi sdk?
The 4.4.1 sdk is not even available to download anymore and if there is no adapter for 5.2.3, then I'm afraid inmobi integration with in mopub is not possible?
I waited a few days and did not get any response back from Inmobi so I decided to do some investigation myself on how to solve this issue. Eventually I can across this website which had a sample app with SDK 5.0.0 but the class seems to work with SDK 5.2.3 without any problems.
https://support.inmobi.com/monetize/integration/mediation-adapters/mopub-adaptor-android-sdk-integration-guide/#getting-started
I had to read the class and make my own adjustments to the adapter so that it will work - their adapter had issues as they were using deprecated classes. So here is the updated adapter:
package com.mopub.nativeads;
import android.app.Activity;
import android.content.Context;
import android.support.annotation.NonNull;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import com.inmobi.ads.InMobiAdRequestStatus;
import com.inmobi.sdk.InMobiSdk;
import com.mopub.common.MoPub;
import com.mopub.common.logging.MoPubLog;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.mopub.common.util.Json.getJsonValue;
import static com.mopub.common.util.Numbers.parseDouble;
import static com.mopub.nativeads.NativeImageHelper.preCacheImages;
/*
* Tested with InMobi SDK 5.2.3
*/
public class InMobiNative extends CustomEventNative {
private static boolean isAppIntialize = false;
private JSONObject serverParams;
private String accountId="XXX";
private long placementId=123L;
#Override
protected void loadNativeAd(#NonNull Activity arg0,
#NonNull CustomEventNativeListener arg1,
#NonNull Map<String, Object> arg2,
#NonNull Map<String, String> arg3) {
// TODO Auto-generated method stub
Log.d("InMobiNativeCustomEvent", "Reached native adapter");
try {
serverParams = new JSONObject(arg3);
} catch (Exception e) {
Log.e("InMobi", "Could not parse server parameters");
e.printStackTrace();
}
Activity activity = null;
if (arg0 instanceof Activity) {
activity = arg0;
} else {
// You may also pass in an Activity Context in the localExtras map
// and retrieve it here.
}
if (activity == null) {
arg1.onNativeAdFailed(NativeErrorCode.NATIVE_ADAPTER_CONFIGURATION_ERROR);
return;
}
try {
accountId = serverParams.getString("accountid");
placementId = serverParams.getLong("placementId");
} catch (JSONException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
if (!isAppIntialize) {
try {
InMobiSdk.init(activity,"accountid");
} catch (Exception e) {
e.printStackTrace();
}
isAppIntialize = true;
}
InMobiSdk.setAreaCode("areacode");
InMobiSdk.setEducation(InMobiSdk.Education.HIGH_SCHOOL_OR_LESS);
InMobiSdk.setGender(InMobiSdk.Gender.MALE);
InMobiSdk.setIncome(1000);
InMobiSdk.setAge(23);
InMobiSdk.setPostalCode("postalcode");
InMobiSdk.setLogLevel(InMobiSdk.LogLevel.DEBUG);
InMobiSdk.setLocationWithCityStateCountry("blore", "kar", "india");
InMobiSdk.setLanguage("ENG");
InMobiSdk.setInterests("dance");
InMobiSdk.setEthnicity(InMobiSdk.Ethnicity.ASIAN);
InMobiSdk.setYearOfBirth(1980);
Map<String, String> map = new HashMap<String, String>();
map.put("tp", "c_mopub");
map.put("tp-ver", MoPub.SDK_VERSION);
final InMobiStaticNativeAd inMobiStaticNativeAd =
new InMobiStaticNativeAd(arg0,
new ImpressionTracker(arg0),
new NativeClickHandler(arg0),
arg1);
inMobiStaticNativeAd.setIMNative(new com.inmobi.ads.InMobiNative(placementId, inMobiStaticNativeAd));
inMobiStaticNativeAd.setExtras(map);
inMobiStaticNativeAd.loadAd();
}
static class InMobiStaticNativeAd extends StaticNativeAd implements com.inmobi.ads.InMobiNative.NativeAdListener {
static final int IMPRESSION_MIN_TIME_VIEWED = 1000;
// Modifiable keys
static final String TITLE = "title";
static final String DESCRIPTION = "description";
static final String SCREENSHOTS = "screenshots";
static final String ICON = "icon";
static final String LANDING_URL = "landingURL";
static final String CTA = "cta";
static final String RATING = "rating";
// Constant keys
static final String URL = "url";
private final Context mContext;
private final CustomEventNativeListener mCustomEventNativeListener;
private final ImpressionTracker mImpressionTracker;
private final NativeClickHandler mNativeClickHandler;
private com.inmobi.ads.InMobiNative mImNative;
InMobiStaticNativeAd(final Context context,
final ImpressionTracker impressionTracker,
final NativeClickHandler nativeClickHandler,
final CustomEventNativeListener customEventNativeListener) {
InMobiSdk.init(context,"9107a61fcda34c969d3f74934a352dcb");
mContext = context.getApplicationContext();
mImpressionTracker = impressionTracker;
mNativeClickHandler = nativeClickHandler;
mCustomEventNativeListener = customEventNativeListener;
}
void setIMNative(final com.inmobi.ads.InMobiNative imNative) {
mImNative = imNative;
}
void setExtras(Map<String,String> map){
mImNative.setExtras(map);
}
void loadAd() {
mImNative.load();
}
// Lifecycle Handlers
#Override
public void prepare(final View view) {
if (view != null && view instanceof ViewGroup) {
com.inmobi.ads.InMobiNative.bind((ViewGroup)view, mImNative);
} else if (view != null && view.getParent() instanceof ViewGroup) {
com.inmobi.ads.InMobiNative.bind((ViewGroup)(view.getParent()), mImNative);
} else {
Log.e("MoPub", "InMobi did not receive ViewGroup to attachToView, unable to record impressions");
}
mImpressionTracker.addView(view, this);
mNativeClickHandler.setOnClickListener(view, this);
}
#Override
public void clear(final View view) {
mImpressionTracker.removeView(view);
mNativeClickHandler.clearOnClickListener(view);
}
#Override
public void destroy() {
//InMobiNative.unbind(arg0);
mImpressionTracker.destroy();
}
// Event Handlers
#Override
public void recordImpression(final View view) {
notifyAdImpressed();
}
#Override
public void handleClick(final View view) {
notifyAdClicked();
mNativeClickHandler.openClickDestinationUrl(getClickDestinationUrl(), view);
mImNative.reportAdClick(null);
}
void parseJson(final com.inmobi.ads.InMobiNative inMobiNative) throws JSONException {
final JSONTokener jsonTokener = new JSONTokener((String) inMobiNative.getAdContent());
final JSONObject jsonObject = new JSONObject(jsonTokener);
setTitle(getJsonValue(jsonObject, TITLE, String.class));
String text = getJsonValue(jsonObject, DESCRIPTION, String.class);
if(text!=null)
setText(text);
final JSONObject screenShotJsonObject = getJsonValue(jsonObject, SCREENSHOTS, JSONObject.class);
if (screenShotJsonObject != null) {
setMainImageUrl(getJsonValue(screenShotJsonObject, URL, String.class));
}
final JSONObject iconJsonObject = getJsonValue(jsonObject, ICON, JSONObject.class);
if (iconJsonObject != null) {
setIconImageUrl(getJsonValue(iconJsonObject, URL, String.class));
}
final String clickDestinationUrl = getJsonValue(jsonObject, LANDING_URL, String.class);
if (clickDestinationUrl == null) {
final String errorMessage = "InMobi JSON response missing required key: "
+ LANDING_URL + ". Failing over.";
MoPubLog.d(errorMessage);
throw new JSONException(errorMessage);
}
setClickDestinationUrl(clickDestinationUrl);
String cta = getJsonValue(jsonObject, CTA, String.class);
if(cta!=null)
setCallToAction(cta);
try {
if(jsonObject.opt(RATING)!=null){
setStarRating(parseDouble(jsonObject.opt(RATING)));
}
} catch (ClassCastException e) {
Log.d("MoPub", "Unable to set invalid star rating for InMobi Native.");
} setImpressionMinTimeViewed(IMPRESSION_MIN_TIME_VIEWED);
}
#Override
public void onAdDismissed(com.inmobi.ads.InMobiNative inMobiNative) {
// TODO Auto-generated method stub
Log.d("InMobiNativeCustomEvent","Native Ad is dismissed");
}
#Override
public void onAdDisplayed(com.inmobi.ads.InMobiNative inMobiNative) {
// TODO Auto-generated method stub
Log.d("InMobiNativeCustomEvent","Native Ad is displayed");
}
#Override
public void onAdLoadFailed(com.inmobi.ads.InMobiNative arg0, InMobiAdRequestStatus arg1) {
// TODO Auto-generated method stub
Log.d("InMobiNativeCustomEvent","Native ad failed to load");
String errorMsg="";
switch (arg1.getStatusCode()) {
case INTERNAL_ERROR:
errorMsg="INTERNAL_ERROR";
break;
case REQUEST_INVALID:
errorMsg="INVALID_REQUEST";
break;
case NETWORK_UNREACHABLE:
errorMsg="NETWORK_UNREACHABLE";
break;
case NO_FILL:
errorMsg="NO_FILL";
break;
case REQUEST_PENDING:
errorMsg="REQUEST_PENDING";
break;
case REQUEST_TIMED_OUT:
errorMsg="REQUEST_TIMED_OUT";
break;
case SERVER_ERROR:
errorMsg="SERVER_ERROR";
break;
case AD_ACTIVE:
errorMsg="AD_ACTIVE";
break;
case EARLY_REFRESH_REQUEST:
errorMsg="EARLY_REFRESH_REQUEST";
break;
default:
errorMsg="NETWORK_ERROR";
break;
}
if (errorMsg == "INVALID_REQUEST") {
mCustomEventNativeListener.onNativeAdFailed(NativeErrorCode.NETWORK_INVALID_REQUEST);
} else if (errorMsg == "INTERNAL_ERROR" || errorMsg == "NETWORK_ERROR") {
mCustomEventNativeListener.onNativeAdFailed(NativeErrorCode.NETWORK_INVALID_STATE);
} else if (errorMsg == "NO_FILL") {
mCustomEventNativeListener.onNativeAdFailed(NativeErrorCode.NETWORK_NO_FILL);
} else if (errorMsg == "REQUEST_TIMED_OUT"){
mCustomEventNativeListener.onNativeAdFailed(NativeErrorCode.NETWORK_TIMEOUT);
}else if(errorMsg == "NETWORK_UNREACHABLE"){
mCustomEventNativeListener.onNativeAdFailed(NativeErrorCode.CONNECTION_ERROR);
}
else {
mCustomEventNativeListener.onNativeAdFailed(NativeErrorCode.UNSPECIFIED);
}
}
#Override
public void onUserLeftApplication(com.inmobi.ads.InMobiNative arg0) {
// TODO Auto-generated method stub
Log.d("InMobiNativeCustomEvent","User left application");
}
#Override
public void onAdLoadSucceeded(com.inmobi.ads.InMobiNative inMobiNative) {
// TODO Auto-generated method stub
Log.v("InMobiNativeCustomEvent", "Ad loaded:"+inMobiNative.getAdContent().toString());
try {
parseJson(inMobiNative);
} catch (JSONException e) {
mCustomEventNativeListener.onNativeAdFailed(NativeErrorCode.INVALID_RESPONSE);
return;
}
final List<String> imageUrls = new ArrayList<String>();
/*final String mainImageUrl = getMainImageUrl();
if (mainImageUrl != null) {
imageUrls.add(mainImageUrl);
}*/
final String iconUrl = getIconImageUrl();
if (iconUrl != null) {
imageUrls.add(iconUrl);
}
preCacheImages(mContext, imageUrls, new NativeImageHelper.ImageListener() {
#Override
public void onImagesCached() {
Log.v("InMobiNativeCustomEvent", "image cached");
mCustomEventNativeListener.onNativeAdLoaded(InMobiStaticNativeAd.this);
}
#Override
public void onImagesFailedToCache(NativeErrorCode errorCode) {
Log.v("InMobiNativeCustomEvent", "image failed to cache");
mCustomEventNativeListener.onNativeAdFailed(errorCode);
}
});
}
}
}
Then you need to read this website telling you more about how to integrate their SDK into your app. You need to copy and paste this into your manifest:
https://support.inmobi.com/android-sdk-integration-guide/#getting-started
<activity android:name="com.inmobi.rendering.InMobiAdActivity"
android:configChanges="keyboardHidden|orientation|keyboard|smallestScreenSize|screenSize"
android:theme="#android:style/Theme.Translucent.NoTitleBar"
android:hardwareAccelerated="true" />
<receiver
android:name="com.inmobi.commons.core.utilities.uid.ImIdShareBroadCastReceiver"
android:enabled="true"
android:exported="true" >
<intent-filter>
<action android:name="com.inmobi.share.id" />
</intent-filter>
</receiver>
Without these classes, the SDK will not initialize and you will get an error in the logs.
Please do read through both websites, I'm just dealing on a high level on how you can solve the integration but there are other stuff you should put into your app to make mopub work successfully with inmobi for Android.
I am building an android app that will be able to read values from a load sensor. The load sensor is connected to a LCD to display the values of weight applied to the sensor and an Arduino board. I am simply building this app to get the weight values from the LCD/load sensor. I am using HC-06 Bluetooth module, and I am able to connect/pair with this device successfully. The 'MainActivity' activity has a 'get data' button to read the data from the load sensor but anytime It is pressed the app freezes. I have been told by the author of the following tutorial that I need to write some 'Handler' method. I have made an attempt with no luck.
I've been following this tutorial but I'm stuck on reading data
https://wingoodharry.wordpress.com/2014/04/15/android-sendreceive-data-with-arduino-using-bluetooth-part-2/
Here is my code :
package com.proj.splate;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
#SuppressWarnings("unused")
public class MainActivity extends Activity {
Button btnscan;
TextView txtArduino, txtString, txtStringLength, calorie;
Handler bluetoothIn;
final int handlerState = 0; //used to identify handler message
private BluetoothAdapter btAdapter = null;
private BluetoothSocket btSocket; //= null;
private StringBuilder recDataString = new StringBuilder();
private ConnectedThread mConnectedThread;
// SPP UUID service - this should work for most devices
private static final UUID BTMODULEUUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
// String for MAC address
private static String address;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Link the buttons and textViews to respective views
btnscan = (Button) findViewById(R.id.scanBtn);
txtString = (TextView) findViewById(R.id.txtString);
txtStringLength = (TextView) findViewById(R.id.testView1);
bluetoothIn = new Handler() {
public void handleMessage(android.os.Message msg) {
if (msg.what == handlerState) {
String readMessage = (String) msg.obj;
recDataString.append(readMessage);
int endOfLineIndex = recDataString.indexOf("~");
if (endOfLineIndex > 0) {
String dataInPrint = recDataString.substring(0, endOfLineIndex);
txtString.setText("Data Received = " + dataInPrint);
int dataLength = dataInPrint.length();
txtStringLength.setText("String Length = " + String.valueOf(dataLength));
if (recDataString.charAt(0) == '#')
{
//get sensor value from string between indices 1-20
String weight = recDataString.substring(1, 20);
//update the textviews with sensor values
calorie.setText(weight + "kg");
}
recDataString.delete(0, recDataString.length());
// strIncom =" ";
dataInPrint = " ";
}
}
}
};
btAdapter = BluetoothAdapter.getDefaultAdapter(); // get Bluetooth adapter
checkBTState();
// Set up onClick listeners for button to scan for data
btnscan.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
mConnectedThread.write("0");
}
});
}
private BluetoothSocket createBluetoothSocket(BluetoothDevice device) throws IOException {
return device.createRfcommSocketToServiceRecord(BTMODULEUUID);
//creates secure outgoing connecetion with BT device using UUID
}
#Override
public void onResume() {
super.onResume();
//Get MAC address from DeviceListActivity via intent
Intent intent = getIntent();
//Get the MAC address from the DeviceListActivty via EXTRA
address = intent.getStringExtra(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
//create device and set the MAC address
BluetoothDevice device = btAdapter.getRemoteDevice(address);
try {
btSocket = createBluetoothSocket(device);
} catch (IOException e) {
Toast.makeText(getBaseContext(), "Socket creation failed", Toast.LENGTH_LONG).show();
}
// Establish the Bluetooth socket connection.
try
{
btSocket.connect();
} catch (IOException e) {
try
{
btSocket.close();
} catch (IOException e2)
{
//insert code to deal with this
}
}
mConnectedThread = new ConnectedThread(btSocket);
mConnectedThread.start();
//I send a character when resuming.beginning transmission to check device is connected
//If it is not an exception will be thrown in the write method and finish() will be called
mConnectedThread.write("x");
}
#Override
public void onPause()
{
super.onPause();
try
{
//Don't leave Bluetooth sockets open when leaving activity
btSocket.close();
} catch (IOException e2) {
//insert code to deal with this
}
}
//Checks that the Android device Bluetooth is available and prompts to be turned on if off
private void checkBTState() {
if(btAdapter==null) {
Toast.makeText(getBaseContext(), "Device does not support bluetooth", Toast.LENGTH_LONG).show();
} else {
if (btAdapter.isEnabled()) {
} else {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, 1);
}
}
}
//create new class for connect thread
private class ConnectedThread extends Thread {
private final InputStream mmInStream;
private final OutputStream mmOutStream;
//creation of the connect thread
public ConnectedThread(BluetoothSocket socket) {
btSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
try {
//Create I/O streams for connection
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
byte[] buffer = new byte[1024];
int bytes;
// Keep looping to listen for received messages
while (true) {
try {
bytes = mmInStream.read(buffer);
bluetoothIn.obtainMessage(handlerState, bytes, -1, buffer).sendToTarget();
} catch (IOException e) {
break;
}
}
}
//write method
public void write(String input) {
byte[] msgBuffer = input.getBytes();//converts entered String into bytes
try {
mmOutStream.write(msgBuffer);//write bytes over BT connection via outstream
} catch (IOException e) {
//if you cannot write, close the application
Toast.makeText(getBaseContext(), "Connection Failed", Toast.LENGTH_LONG).show();
finish();
}
}
public class BluetoothInHandler extends Handler{
private Looper sLooper = null;
private Handler mWorkerThreadHandler;
final int handlerState = 0; //used to identify handler message
protected class WorkerArgs {
Handler handler;
String input;
String output;
}
public BluetoothInHandler() {
super();
synchronized (BluetoothInHandler.class) {
if (sLooper == null) {
HandlerThread thread = new HandlerThread("AsyncWorker");
thread.start();
sLooper = thread.getLooper();
}
}
mWorkerThreadHandler = new WorkerHandler(sLooper);
}
#Override
public void handleMessage(Message msg) {
if (msg.what == handlerState) {
WorkerArgs args = (WorkerArgs) msg.obj;
String readMessage = args.output;
//your job;
} else {
super.handleMessage(msg);
}
}
public void write(String input) {
WorkerArgs args = new WorkerArgs();
args.handler = this;
args.input = input;
Message message = mWorkerThreadHandler.obtainMessage(handlerState);
message.obj = args;
mWorkerThreadHandler.sendMessage(message);
}
protected class WorkerHandler extends Handler {
public WorkerHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
if (msg.what == handlerState) {
WorkerArgs args = (WorkerArgs) msg.obj;
byte[] buffer;
//the code here run in a thread, not in the ui thread
//do your job like:
byte[] bytes = mmInStream.read(buffer);
args.output = new String(bytes);
Message message = args.handler.obtainMessage(handlerState);
message.obj = args;
message.sendToTarget();
}
}
}
}
}//ConnectedThread End
}
Here is my Arduino Code:
#include <LiquidCrystal.h>
int led = 13;
int button = 12;
LiquidCrystal lcd(9, 8, 4, 5, 6, 7);
// Pins used for inputs and outputs********************************************************
float sensorValue1;
float containerValue;
char inbyte = 0;
int flag;
const int numReadings = 50;
int readings[numReadings];
int index = 0;
int total = 0;
int average = 0;
//*******************************************************************************************
void setup()
{
pinMode(led, OUTPUT);
digitalWrite(led, HIGH);
Serial.begin(9600);
for (int thisReading = 0; thisReading < numReadings; thisReading++)
{
readings[thisReading] = 0;
}
lcd.begin(16, 2); //change to 16, 2 for smaller 16x2 screens
lcd.clear();
lcd.print("hello, world!");
delay (1000);
lcd.clear();
delay (500);
}
void loop()
{
digitalWrite(led, HIGH);
readSensor2(); //DONE
printLCD(); //DONE
return;
sendAndroidValues();
//when serial values have been received this will be true
if (Serial.available() > 0)
{
inbyte = Serial.read();
if (inbyte == '0')
{
//LED off
digitalWrite(led, LOW);
}
if (inbyte == '1')
{
//LED on
digitalWrite(led, HIGH);
}
}
//delay by 2s. Meaning we will be sent values every 2s approx
//also means that it can take up to 2 seconds to change LED state
delay(2000);
void readSensor2()
{
total = total - readings[index];
readings[index] = analogRead(A0);
total = total + readings[index];
index = index + 1;
if (index >= numReadings)
{
index = 0;
}
average = total / numReadings;
//sensorValue1 = (analogRead(A0) - 330)* i;
//delay(200);
Serial.println(average);
delay(100);
if( digitalRead(button) == HIGH && flag == 1)
{
flag = 0;
containerValue = 0;
}
else if (digitalRead(button) == HIGH && flag != 1)
{
flag = 1; //when the button is pressed the initially sesnsor
containerValue = sensorValue1;
delay(10);
}
//Serial.println(digitalRead(button));
delay (1000);
}
//sends the values from the sensor over serial to BT module
void sendAndroidValues()
{
//puts # before the values so our app knows what to do with the data
Serial.print('#');
//for loop cycles through 4 sensors and sends values via serial
Serial.print(sensorValue1);
Serial.print('+');
//technically not needed but I prefer to break up data values
//so they are easier to see when debugging
Serial.print('~'); //used as an end of transmission character - used in app for string length
Serial.println();
delay(5000); //added a delay to eliminate missed transmissions
}
void printLCD()
{
lcd.setCursor(4, 0);
lcd.print(" GRAMS ");
lcd.setCursor(4, 1);
lcd.print(sensorValue1);
}
Not sure if this is much of a problem, since it doesn't look like you're doing a ton of work in your handleMessage(Message msg) method, but your Handler is still being created on the main thread. To use a Handler to process background messages, you'll need to pass it a separate Looper. An easy way to to do this would be to use the HandlerThread class to provide your Looper.
Once you do this, however, you'll need to post results back to your UI thread from your handleMessage(Message msg) since you can't modify UI elements (or use Toasts, see your "write" method) from threads other than the main thread (See Activity.runOnUiThread(Runnable runnable)).
Also, you're still using your "ConnectedThread" object as an object by how you're calling your methods from within your onClickListener...so it's not really doing what you're intending it to do in that regard. To verify this, use Looper.myLooper() == Looper.getMainLooper() to see which thread is currently executing. I'd advise more towards the Handler solution suggested above, and posting Runnables for execution.
Lastly, since you're ConnectedThread runs continously in a while(true) loop without pauses, this could be flooding your handler potentially as well.