First of all sorry to repost the question as I didn't post my code earlier just written some lines now I am failing to explain.So posting the question again with codes.
I have written a code that will log the acceleromter data and save the data in a csv file. What I need to do is I have to run the acceleromter in background as a service. So,I m done with writing the codes for
1.running the accelerometer,
2.shown the data in textbox,
3.write the data in a csv file.
Things that are left is making it a service. I m giving the code below(Howfar I have done)
#SuppressWarnings("deprecation")
public class AccelerometerVaue extends Activity implements SensorListener {
SensorManager sm = null;
TextView xacc= null;
TextView yacc = null;
TextView zacc = null;
TextView xorient = null;
TextView yorient = null;
TextView zorient = null;
TextView text = null;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sm = (SensorManager) getSystemService(SENSOR_SERVICE);
setContentView(R.layout.activity_main);
xacc = (TextView) findViewById(R.id.xvalue);
yacc = (TextView) findViewById(R.id.yvalue);
zacc = (TextView) findViewById(R.id.zvalue);
xorient = (TextView) findViewById(R.id.xvalues);
yorient = (TextView) findViewById(R.id.yvalues);
zorient = (TextView) findViewById(R.id.zvalues);
}
#SuppressLint("SdCardPath")
public void onSensorChanged(int sensor, float[] values) {
synchronized (this) {
if (sensor == SensorManager.SENSOR_ORIENTATION) {
xorient.setText("Orientation X: " + values[0]);
yorient.setText("Orientation Y: " + values[1]);
zorient.setText("Orientation Z: " + values[2]);
}
if (sensor == SensorManager.SENSOR_ACCELEROMETER) {
// Time now = new Time();
// now.setToNow();
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
String currentDateandTime = sdf.format(new Date());
Log.d("Time",currentDateandTime);
xacc.setText("Accel X: " + values[0]);
yacc.setText("Accel Y: " + values[1]);
zacc.setText("Accel Z: " + values[2]);
String res=String.valueOf(currentDateandTime+"#"+values[0])+"#"+String.valueOf(values[1])+"#"+String.valueOf(values[2]);
Log.d("test", res);
CSVWriter writer = null;
try
{
//Log.d("check","pasla");
//Environment.getExternalStorageDirectory().getPath();
writer = new CSVWriter(new FileWriter("/sdcard/AccelData.csv",true), ',');
String[] entries = res.split("#"); // array of your values
writer.writeNext(entries);
//FileWriter
writer.close();
}
catch (IOException e)
{
//error
}
}
}
}
public void onAccuracyChanged(int sensor, int accuracy) {
String tag = null;
Log.e(tag,"onAccuracyChanged: " + sensor + ", accuracy: " + accuracy);
}
#Override
protected void onResume() {
super.onResume();
sm.registerListener(this,
SensorManager.SENSOR_ORIENTATION |
SensorManager.SENSOR_ACCELEROMETER,
SensorManager.SENSOR_DELAY_NORMAL);
}
#Override
protected void onStop() {
sm.unregisterListener(this);
super.onStop();
}
}
So, now I need to run a background service which will keep taking accelerometer data in background and also keep saving into that csv file. How can I do this? One more I like to ask is it possible to take the acc data after a certain period of time? Suppose here I m logging all the data continuously which is huge and thew battery drain will be huge. So, I need to implemented the service in such a way so that it will run in background for 15mins and log the data for 10 seconds at the beginning of each minute.
I have just replied to a similar question.
You can use Android's scheduling mechanism, called AlarmManager, to schedule your services.
There is a problem inerent to this approach, though: when the system is in battery-saving sleep state, your service has to acquire a wake lock in order to execute properly, then when finished release the wake lock for the system to go back to sleep state. Implementing this wake lock acquisition/release mechanism is not a trivial task.
I recommend using Commonsware's WakefulIntentService in order to avoid writing your own wake lock acquisition/release mechanism for your service. It's very easy to use. You will basically declare a class that extends the WakefulIntentService class and override its doWakefulWork() method. In that method you will poll for accelerometer data and write it to a file. I'll just let you down in the part of displaying the data in the screen, I don't know how to do that (I suppose you will have to perform a bind to the service though). <:)
Related
I have a wearable app. The app after it finishes has data like time/date, UUID, Geo location, parameters selected displayed in front of me like a Data Report or Log in several TextViews underneath each other. Like a list. I want this data to be transferred from my wearable device to my android phone.
Now I have to ask does the WearOS app the pairs the phone with the watch enables such a thing? Like can the data be sent through it? OR what exactly can I do? I read about Sync data items with the Data Layer API in the documentation, but I'm not sure if the code snippets provided would help achieve what I want.
public class MainActivity extends Activity {
private static final String COUNT_KEY = "com.example.key.count";
private DataClient dataClient;
private int count = 0;
...
// Create a data map and put data in it
private void increaseCounter() {
PutDataMapRequest putDataMapReq = PutDataMapRequest.create("/count");
putDataMapReq.getDataMap().putInt(COUNT_KEY, count++);
PutDataRequest putDataReq = putDataMapReq.asPutDataRequest();
Task<DataItem> putDataTask = dataClient.putDataItem(putDataReq);
}
...
}
The data I display in the textviews are called through methods that I call things like: getLocation, getUUID, getDateTime, getSelections, etc... when I click a button I call them in the setOnClickListener. I want this data in the TextViews to be placed in a file or something like that and send them over to the mobile phone from the watch when they're generated.
private void getDateTime()
{
SimpleDateFormat sdf_date = new SimpleDateFormat("dd/MM/yyyy");
SimpleDateFormat sdf_time = new SimpleDateFormat("HH:mm:ss z");
String currentDate= sdf_date.format(new Date());
String currentTime= sdf_time.format(new Date());
textView_date_time.setText("Date: "+currentDate+"\n"+"Time: "+currentTime);
}
#SuppressLint("SetTextI18n")
private void getUUID()
{
// Retrieving the value using its keys the file name
// must be same in both saving and retrieving the data
#SuppressLint("WrongConstant") SharedPreferences sh = getSharedPreferences("UUID_File", MODE_APPEND);
// The value will be default as empty string because for
// the very first time when the app is opened, there is nothing to show
String theUUID = sh.getString(PREF_UNIQUE_ID, uniqueID);
// We can then use the data
textView_UUID.setText("UUID: "+theUUID);
}
#SuppressLint("SetTextI18n")
private void getSelections()
{
textView_data_selected.setText("Tool No.: "+c.getToolNo()+
"\nTool Size: " +c.getToolSizeStr()+
"\nFrom Mode: " +c.getCurrentModeStr()+
"\nGoto Mode: " +c.getModeStr()+
"\nMethod: " +c.getMethodStr()+
"\nBit Duration: " +c.getBitDuration()+
"\nUpper bound" +c.getUpStageValue()+
"\nLower bound: "+c.getDownStageValue());
}
The above are examples of the methods I use to get the data. then I call them here:
gps_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (Build.VERSION.SDK_INT >= 26) {
getLocation();
getDateTime();
getUUID();
getSelections();
}
else
{
//ActivityCompat.requestPermissions(get_location.this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
Toast.makeText(get_location.this,"Build SDK too low",Toast.LENGTH_SHORT);
}
}
});
Now how do I take all this and send it over from my device to the the phone?
Note: The data report I want to send as a file, I want it done subtly like something done in the background. I don't know what else to do or where to look.
You have two options if you want to use the Data Layer, one is to use the MessageClient API to bundle your data up in a message and send it directly to the handheld. The easiest here would be to create an arbitrary JSONObject and serialize your data as a JSON string you can stuff into a message. For example:
try {
final JSONObject object = new JSONObject();
object.put("heart_rate", (int) event.values[0]);
object.put("timestamp", Instant.now().toString());
new MessageSender("/MessageChannel", object.toString(), getApplicationContext()).start();
} catch (JSONException e) {
Log.e(TAG, "Failed to create JSON object");
}
In my case, I do this in my onSensorChanged implementation, but you can insert this wherever you are updating your text.
MessageSender is just a threaded wrapper around the MessageClient:
import java.util.List;
class MessageSender extends Thread {
private static final String TAG = "MessageSender";
String path;
String message;
Context context;
MessageSender(String path, String message, Context context) {
this.path = path;
this.message = message;
this.context = context;
}
public void run() {
try {
Task<List<Node>> nodeListTask = Wearable.getNodeClient(context.getApplicationContext()).getConnectedNodes();
List<Node> nodes = Tasks.await(nodeListTask);
byte[] payload = message.getBytes();
for (Node node : nodes) {
String nodeId = node.getId();
Task<Integer> sendMessageTask = Wearable.getMessageClient(context).sendMessage(nodeId, this.path, payload);
try {
Tasks.await(sendMessageTask);
} catch (Exception exception) {
// TODO: Implement exception handling
Log.e(TAG, "Exception thrown");
}
}
} catch (Exception exception) {
Log.e(TAG, exception.getMessage());
}
}
}
The other option is to create a nested hierarchy of data items in the Data Layer and implement DataClient.OnDataChangedListener on both sides, such that changes that are written in on one side are automatically synchronized with the other. You can find a good walkthrough on how to do that here.
For your specific case, just packing it in a JSON object would probably be the simplest. The writing out to your preferred file format you can then implement on the handheld side without needing to involve the wear side.
I am trying to log the exception plus the user navigation for x amount of time. For example, when my application got an exception I will append it in a text file. Now from that point of time of time, I need to log only for a certain time. e.g., 1 hour. Is it possible to do it? This is the code I wrote to get the exception information and log it in a file.
Please someone help me with this. Thanks in advance.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Thread.setDefaultUncaughtExceptionHandler(handleAppCrash);
}
private Thread.UncaughtExceptionHandler handleAppCrash =
new Thread.UncaughtExceptionHandler() {
#SuppressLint("LongLogTag")
#Override
public void uncaughtException(Thread thread, Throwable ex) {
if (!file.exists()) {
file.mkdir();
}
try {
data = android_version + "#" + Device + "#" + username + "#" + version + "#" + dates + "#" + Logtrace;
File gpxfile = new File(file, fname);
FileWriter writer = new FileWriter(gpxfile,true);
writer.append(data);
writer.flush();
writer.close();
} catch (
Exception e) {
e.printStackTrace();
}
}
};
You are looking for a way to
restart the app
write more logs to the same file that you created in the UncaughtExceptionHandler.
Firstly, to restart the app, you can take the following steps:
Created a pending intent, e.g., in your onCreate (where Intent intent has class scope, already defined, i.e., not just defined within onCreate):
intent = PendingIntent.getActivity(
YourApplication.getInstance().getBaseContext(),
0,
new Intent(getIntent()),
getIntent().getFlags());
After your try/catch in your UncaughtExceptionHandler, start an alarm to trigger your app in some amount of time, e.g., 1 second; and you must follow this with a System.exit();. This is so the current dying app will properly quit, so that in 1 second, when the alarm triggers, it will start the app again (but it won't if the app is still running).
AlarmManager mgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, intent);
System.exit(2);
You could optionally store the name of the file (fname in your code) to SharedPreferences (for writing to the same file when the app restarts). Or it could be a fixed hardcoded name that your app knows, and doesn't need to save the name.
You could saved a Boolean in SharedPreferences to let your app know that you are restarting from an uncaught exception.
Secondly, whenever the app starts:
Check the Boolean in SharedPreferences; if it is a normal start, proceed like normal.
If it is a restart after uncaught exception, then retrieve the file name from SharedPreferences (or get it hard coded), then you can write more logs to the file. As in Android, a file is uniquely determined by path and file name. With the same file name, you can open the same file.
Define a background service
To do anything in the background for a prolonged time you should use a service. I'm using a JobService in this example.
<service android:name="org.example.LogService"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE"
android:process=":logprocess"/>
Note the process tag, it is important, because you'll want to kill your current process after an uncaught exception.
public class LogService extends JobService {
private Thread thread;
#Override
public boolean onStartJob(final JobParameters params) {
if (!file.exists()) {
file.mkdir();
}
thread = new Thread(() -> {
try {
data = params.getExtras().getString("data");
File gpxfile = new File(file, fname);
FileWriter writer = new FileWriter(gpxfile,true);
writer.append(data);
//continue to write your logs to the file here for as long as you want. you could copy logcat to the file for example.
writer.flush();
writer.close();
} catch (Exception e) {
e.printStackTrace();
}
jobFinished(params, false);
});
thread.start();
return true;
}
#Override
public boolean onStopJob(JobParameters params) {
thread.interrupt();
return true;
}
}
Call your background service
public void uncaughtException(Thread thread, Throwable ex) {
JobScheduler scheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
PersistableBundle extras = new PersistableBundle();
extras.putString("data", android_version + "#" + Device + "#" + username + "#" + version + "#" + dates + "#" + Logtrace);
JobInfo.Builder builder = new JobInfo.Builder(0, new ComponentName(context, LogService.class))
builder.setExtras(extras);
builder.setOverrideDeadline(1000);
scheduler.schedule(builder.build());
//stop the current process.
Process.killProcess(Process.myPid());
System.exit(10);
}
Killing the current process is optional but recommended, the application could be in a bad state after an uncaught exception. If you want to restart your application you can call startActivity from the LogService.
Note:
You've not given any details on what exactly you want to log for x amount of time, so this code only has a comment where the log collection goes.
Note 2:
This code was adapted from the ACRA project of which I am a maintainer, specifically manifest JobSenderService DefaultSenderScheduler and ProcessFinisher
I'm working in an application which must send a GPS location every 5 seconds to the server when I choose (auto send button on). I'm new with android so I don't know how I can make an on/off button and how can I invoke the method that sends the data every 5 seconds when the button is on.
The method which it must invoke every 5 seconds:
public void postData() throws ClientProtocolException, IOException, Exception {
String longitude="UK";
String latitude="UK";
String altitiude="UK";
String time="";
String speed="";
getCurrentLocation(); // gets the current location and update mobileLocation variables
if (mobileLocation != null) {
locManager.removeUpdates(locListener); // This needs to stop getting the location data and save the battery power.
longitude = ""+mobileLocation.getLongitude();
latitude = "" + mobileLocation.getLatitude();
altitiude = "" + mobileLocation.getAltitude();
String accuracy = "Accuracy" + mobileLocation.getAccuracy();
time = "" + mobileLocation.getTime();
speed =""+ (int)(4*mobileLocation.getSpeed());
editTextShowLocation.setText(longitude + "\n" + latitude + "\n"
+ altitiude + "\n" + accuracy + "\n" + time+ "\n" + speed);
} else {
editTextShowLocation.setText("Sorry, location is not determined");
}
String url = "http://www.itrack.somee.com/post.aspx?id="+"f1"+"&long="+longitude+"&lat="+latitude+"&alt="+altitiude+"&speed="+speed;
// Create a new HttpClient and Post Header
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(url);
try {
// Execute HTTP Post Request
HttpResponse response = httpclient.execute(httppost);
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
} catch (IOException e) {
// TODO Auto-generated catch block
}
}
I have faced exactly the same problem, sending location periodically. I've used a handler and its postDelayed method.
The periodic call part of my code looks like this:
private final int FIVE_SECONDS = 5000;
public void scheduleSendLocation() {
handler.postDelayed(new Runnable() {
public void run() {
sendLocation(); // this method will contain your almost-finished HTTP calls
handler.postDelayed(this, FIVE_SECONDS);
}
}, FIVE_SECONDS);
}
Then you just need to call scheduleSendLocation when you want to start your period calls.
Ridcully is right, there is probably no reason to send the current location every 5 seconds. Here is the rational behind that:
You really only care about 2 things about the users location:
Where are they right now?
Have they moved since I got their first location?
So once you get a satisfactory initial location, you can just register to get callbacks whenever the users moves like this:
private LocationListener mLocationListener;
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mLocationListener = new LocationListener() {
#Override
public void onLocationChanged(final Location location) {
updateLocation(location);
}
#Override
public void onStatusChanged(final String provider,
final int status, final Bundle extras) {
}
#Override
public void onProviderEnabled(final String provider) {
}
#Override
public void onProviderDisabled(final String provider) {
}
};
}
That being said, you could obviously do what these others have said and run the timer every 5 seconds. The thing is, most good locations take 10-20 seconds to run, so you might only want to run it in that interval. Also FYI, this WILL kill battery
Look at the AlarmManager class http://developer.android.com/reference/android/app/AlarmManager.html and particularly the setRepeating function. Its going to be a bit more complicated than you'd like though.
You can use a Timer. But I think it would be better if you only send the position of it has changed a certain distance from the last one you sent. This way you'd send way less data without losing any information.
I'm developing an application and I don't know how can I get CPU usage and temperature, example in a textview.
I try with TYPE_AMBIENT_TEMPERATURE to get temperature, but it doesn't work.
Logs say that "i haven't the sensor", but by using other apps in the play store I get the temperature and freq..
The code works fine if I use other sensor like TYPE_GYROSCOPE or other, so I don't understand how TYPE_AMBIENT_TEMPERATURE doesn't work..
Sorry for my bad english...and please help me..
for the CPU frequency you can use
public static int[] getCPUFrequencyCurrent() throws Exception {
int[] output = new int[getNumCores()];
for(int i=0;i<getNumCores();i++) {
output[i] = readSystemFileAsInt("/sys/devices/system/cpu/cpu"+String.valueOf(i)+"/cpufreq/scaling_cur_freq");
}
return output;
}
you might want to use this one too:
public static int getNumCores() {
//Private Class to display only CPU devices in the directory listing
class CpuFilter implements FileFilter {
#Override
public boolean accept(File pathname) {
//Check if filename is "cpu", followed by a single digit number
if(Pattern.matches("cpu[0-9]+", pathname.getName())) {
return true;
}
return false;
}
}
try {
//Get directory containing CPU info
File dir = new File("/sys/devices/system/cpu/");
//Filter to only list the devices we care about
File[] files = dir.listFiles(new CpuFilter());
//Return the number of cores (virtual CPU devices)
return files.length;
} catch(Exception e) {
//Default to return 1 core
return 1;
}
}
for the temperature (https://stackoverflow.com/a/11931903/1031297)
public class TempSensorActivity extends Activity, implements SensorEventListener {
private final SensorManager mSensorManager;
private final Sensor mTempSensor;
public TempSensorActivity() {
mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
mTempSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_AMBIENT_TEMPERATURE);
}
protected void onResume() {
super.onResume();
mSensorManager.registerListener(this, mTempSensor, SensorManager.SENSOR_DELAY_NORMAL);
}
protected void onPause() {
super.onPause();
mSensorManager.unregisterListener(this);
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
public void onSensorChanged(SensorEvent event) {
}
PS. You first need to check if the sensor is present...If it isn't, there's nothing that can be done. I guess some of the apps lie.
PS2. You can always reverse engineer an app to see how they display the temperature ;)
this is because your device simply doesn't have the thermometer. A lot of older devices don't have it.
Android documentation says devices "MAY" have these sensors built in, but are not "required" to have them.
the other apps that are showing you the temperature, are calculating by their own methods (which may all be different to certain extents)
I am currently in the process of making my own app that measures CPU temperatures myself...
As OWADVL answered, you can ready the temperature also as a system file, like this:
int temperature = readSystemFileAsInt("sys/class/thermal/thermal_zone0/temp");
note that the readSystemFileAsInt is not a system call. I found the implementation here
private static int readSystemFileAsInt(final String pSystemFile) throws Exception {
InputStream in = null;
try {
final Process process = new ProcessBuilder(new String[] { "/system/bin/cat", pSystemFile }).start();
in = process.getInputStream();
final String content = readFully(in);
return Integer.parseInt(content);
} catch (final Exception e) {
throw new Exception(e);
}
}
private static final String readFully(final InputStream pInputStream) throws IOException {
final StringBuilder sb = new StringBuilder();
final Scanner sc = new Scanner(pInputStream);
while(sc.hasNextLine()) {
sb.append(sc.nextLine());
}
return sb.toString();
}
About the CPU usage (load) you can look at this question and already working solution by Souch at his gitHub here
I am a New B to Android. I have been Able to get the Battery Status/Level with the Following Code:
private void BattStatus() {
BroadcastReceiver batteryLevelReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
context.unregisterReceiver(this);
int rawlevel = intent.getIntExtra("level", -1);
int scale = intent.getIntExtra("scale", -1);
int level = -1;
if (rawlevel >= 0 && scale > 0) {
level = (rawlevel * 100) / scale;
}
batteryLevel = level;
BattStatus.setText("Battery Level : " + batteryLevel + "%");
}
};
IntentFilter batteryLevelFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
registerReceiver(batteryLevelReceiver, batteryLevelFilter);
}
I would Like to Store the Battery Level In A text file (Using a thread). Code :
public final Runnable DBThread = new Runnable() {
String AllInfo = batteryLevel+"%"+" , "+new SimpleDateFormat("HH:mm , dd.MM.yy ").format(new Date());
public void run() {
try {
Log.d("DBThread","Battery :"+batteryLevel);
Log.d("DBThread","Updating DB");
myDbHelper.CreateAndWriteFile(sdDir+"/", AllInfo );
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mHandler.postAtTime(this, SystemClock.uptimeMillis() + 2000);
Log.d("DBThread","Updated DB");
Log.d("DBThread",AllInfo);
}
Unfortunately the Battery Status/Level returns 0% in the text file, when I test it using the Log function in the thread it returns the correct value.
Please could some one be so kind to tell me what I am doing wrong or what I am not doing, and maybe provide me with a code snippet as I am new to Development.And Sorry If My Post is incorrect First timer on Stack Overflow :)
Thank you very much!
This is not a Thread. This is a Runnable, which is a piece of code that is made to run in a Thread.
In your case, it runs in the handler thread, most likely the UI Thread.
You probably start your thread before receiving the battery status, hence writing the default value (0) to the file.
You don't need a thread for that. You can write to the file immediately after your receive the broadcast, in the onReceive method.
Edit
There are a few things that don't work in your code. You unregister the broadcast receiver, hence you don't receive the battery level after the first time.
You write the batteryLevel value without knowing if it has indeed been modified
You write every 2 seconds without knowing there has been a change.
I would suggest that you don't unregister the BR, so you receive all battery level change. Then, in the onReceive, you append to the file the date and new value.