I'm building an Android Wear service which runs in the background and logs device data every three minutes. For this logging, I am using a Handler, which records the values and then has an interval of three minutes. This will be used to monitor user behaviour for one month, and as such it should not randomly stop.
I have also used android.intent.action.BOOT_COMPLETED in my manifest and this successfully runs the application whenever the watch is booted.
My issue is that the service can run correctly for 12 hours...and then just suddenly stop. The amount of time appears to be non-deterministic, as sometimes it will stop after 40 minutes. I suspect it's being killed by Android, but in this case I would like it to restart. I have included return START_STICKY in my service and this should minimise the chance of it being killed.
In some solutions, I have seen onDestroy() overridden and a refresh broadcast being sent to the service. While this appears to work, the onDestroy() function is being called every time the Handler completes one piece of work. This leads to the service restarting every three minutes, rather than when the application is actually killed by Android.
I have also looked at the intent actions to see whether my service could be called at regular intervals. However, aside from android.intent.action.BOOT_COMPLETED, all the useful ones cannot be registered in the Manifest file. Since the service will not be running, registerReceiver() would serve little purpose.
Does anybody know of a technique to either a) guarantee a service will not be killed by Android; or b) guarantee that a service will always be restarted after it has been killed. Any help would be greatly appreciated, as I've even started considering writing a Cron job on the device and setting it to execute my app every three minutes! I've also looked at the AlarmManager class, but I fear it is as likely to be killed if running for long periods.
Please find my code below: (AndroidManifest.xml)
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.study">
<uses-feature android:name="android.hardware.type.watch" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#android:style/Theme.DeviceDefault">
<receiver android:name="com.example.study.MyServiceManager" android:enabled="true">
<intent-filter>
<action android:name="com.example.study.RestartAction" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<activity
android:name="com.example.study.MainActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name="com.example.study.RecordService"
android:exported="false" />
</application>
</manifest>
RecordService.java
package com.example.study;
import android.Manifest;
import android.app.AlarmManager;
import android.app.IntentService;
import android.app.KeyguardManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Location;
import com.google.android.gms.location.LocationServices;
import android.os.Build;
import android.os.Handler;
import android.os.PowerManager;
import android.provider.Settings;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.text.TextUtils;
import com.google.android.gms.location.*;
import com.google.android.gms.tasks.OnSuccessListener;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutionException;
public class RecordService extends IntentService {
private static Context context;
private final static int INTERVAL = 1000 * 5; // 1 minutes
Handler handler = new Handler();
Location myLocation;
private FusedLocationProviderClient mFusedLocationClient;
SensorManager sensorManager;
SensorManager gyroSensorManager;
SensorManager compassSensorManager;
SensorEventListener sensorEventListener;
float[] accValues;
float[] gyroValues;
float[] compassValues;
Runnable handlerTask = new Runnable() {
#Override
public void run() {
try {
recordData();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.postDelayed(handlerTask, INTERVAL);
}
};
public RecordService() {
super("RecordService");
}
#Override
protected void onHandleIntent(#Nullable Intent intent) {
handlerTask.run();
}
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
public void recordData() throws ExecutionException, InterruptedException {
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(MainActivity.getAppContext());
boolean fineLocationGranted = ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
boolean coarseLocationGranted = ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED;
boolean isLocationEnabled = isLocationEnabled(this);
if(fineLocationGranted && coarseLocationGranted && isLocationEnabled) {
long startTime = System.currentTimeMillis();
long timeWaiting = 0L;
mFusedLocationClient.getLastLocation()
.addOnSuccessListener(MainActivity.getActivity(), new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
if (location != null) {
myLocation = location;
} else {
System.out.print("");
}
}
});
do {
timeWaiting = System.currentTimeMillis() - startTime;
} while (myLocation == null && timeWaiting < 200);
}
List<PackageInfo> packages = getPackageManager().getInstalledPackages(PackageManager.GET_PERMISSIONS);
KeyguardManager kg = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
boolean isLocked = kg.isDeviceSecure();
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
gyroSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
compassSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
sensorEventListener = new SensorEventListener() {
#Override
public void onSensorChanged(SensorEvent sensorEvent) {
if(sensorEvent.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
accValues = sensorEvent.values;
} else if(sensorEvent.sensor.getType() == Sensor.TYPE_GYROSCOPE){
gyroValues = sensorEvent.values;
} else if(sensorEvent.sensor.getType() == Sensor.TYPE_ORIENTATION) {
compassValues = sensorEvent.values;
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int i) {}
};
try {
sensorManager.registerListener(sensorEventListener, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
gyroSensorManager.registerListener(sensorEventListener, sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE), SensorManager.SENSOR_DELAY_NORMAL);
compassSensorManager.registerListener(sensorEventListener, sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION), SensorManager.SENSOR_DELAY_NORMAL);
} catch(SecurityException e) {
e.printStackTrace();
}
long startTime2 = System.currentTimeMillis();
long timeWaiting2 = 0L;
do {
timeWaiting2 = System.currentTimeMillis() - startTime2;
} while((accValues == null || gyroValues == null || compassValues == null) && timeWaiting2 < 200);
StringBuilder builder = new StringBuilder();
builder.append("G" + (isLocationEnabled ? 1 : 0));
builder.append(" L" + (isLocked ? 1 : 0));
if(accValues != null && gyroValues != null && compassValues != null) {
builder.append(" ACX" + accValues[0]);
builder.append(" ACY" + accValues[1]);
builder.append(" ACZ" + accValues[2]);
builder.append(" GYX" + gyroValues[0]);
builder.append(" GYY" + gyroValues[1]);
builder.append(" GYZ" + gyroValues[2]);
builder.append(" CMX" + gyroValues[0]);
builder.append(" CMY" + gyroValues[1]);
builder.append(" CMZ" + gyroValues[2]);
}
if(myLocation != null) {
builder.append(" LT" + myLocation.getLatitude());
builder.append(" LN" + myLocation.getLongitude());
}
builder.append("\n");
for(PackageInfo info: packages) {
int lastDot = info.packageName.lastIndexOf('.');
builder.append(info.packageName + "\n");
if(info.requestedPermissions != null) {
for (String rqprm : info.requestedPermissions) {
int dot = rqprm.lastIndexOf('.');
builder.append(rqprm.substring(dot != -1 ? dot + 1 : 0) + " ");
}
builder.append("\n");
for (int permflag : info.requestedPermissionsFlags) {
builder.append("" + permflag + " ");
}
builder.append("\n");
}
}
SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd--HH-mm-ss");
String currentDateString = sdf.format(new Date());
File log = new File("/sdcard/Recordings/" + currentDateString);
try {
if (!log.exists()) {
log.createNewFile();
}
BufferedWriter writer = new BufferedWriter(new FileWriter(log, true));
writer.append(builder.toString());
writer.newLine();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static boolean isLocationEnabled(Context context) {
int locationMode = 0;
String locationProviders;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
try {
locationMode = Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.LOCATION_MODE);
} catch (Settings.SettingNotFoundException e) {
e.printStackTrace();
return false;
}
return locationMode != Settings.Secure.LOCATION_MODE_OFF;
} else {
locationProviders = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
return !TextUtils.isEmpty(locationProviders);
}
}
MainActivity.java
package com.example.study;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.widget.TextView;
public class MainActivity extends Activity {
private TextView mTextView;
private static Context context;
private static MainActivity activity;
Intent serviceIntent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MainActivity.context = getApplicationContext();
activity = this;
serviceIntent = new Intent(this, RecordService.class);
startForegroundService(serviceIntent)
startService(serviceIntent);
}
public static Context getAppContext() {
return MainActivity.context;
}
public static MainActivity getActivity() {
return activity;
}
}
MyServiceManager.java
package com.example.study;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
public class MyServiceManager extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent myIntent = new Intent(context, MainActivity.class);
myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(myIntent);
}
}
}
Related
-I am developing an application that records user location in a .csv file and uploads them to firebase storage and I've written a service to accomplish this. The service needs to run indefinitely until the user stops it (by unchecking a switch from the activity that launched the service). The service runs in foreground and after running for 15-20 minutes, the phone manager app gives "resource intensive app found" notification and kills the service. onDestroy() never gets called!. I return START_STICKY which is supposed to recreate the service and call onStartCommand() again but the service never gets created again!
I've seen some people write workarounds for this problem but they target specific android versions. My app targets android Pie and I haven't seen any "generic" solution to this problem yet. All solutions are either device/brand specific or API level specific. For now I'm testing the app on Huawei Y7 prime 2018 (Android O) and on my device, i got around this by manually disallowing the phone manager app to manage my application, this way the service does run indefinitely until the user kills it from the app. The nature of the application is such that i need minimum user engagement and i don't expect the users to go through the hassle of manually disabling my app from battery optimizer/phone manager app. My LocationService.java class is attached, if somebody could please provide either a better implementation of this service or some generic method to keep it alive, that'd be great. Even some hack to make sure that onDestroy() gets called before the system kills the application would work!
package com.example.bumps;
import android.Manifest;
import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.IBinder;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.core.content.ContextCompat;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.storage.FirebaseStorage;
import com.google.firebase.storage.StorageReference;
import com.google.firebase.storage.UploadTask;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Type;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class LocationService extends Service implements LocationListener {
private static final String CHANNEL_ID = "LocationServiceChannel";
private static final int ONGOING_NOTIFICATION_ID = 1;
public static final String PREFS_TAG = "PendingUploadPrefs";
private LocationManager locationManager;
DecimalFormat numberFormat = new DecimalFormat("#.000");
DecimalFormat coordinatesFormat = new DecimalFormat("#.00000");
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
SimpleDateFormat sdfForDir = new SimpleDateFormat("dd-MM-yyyy_hh:mm:ss");
File locationDirectory;
String currentDataDirectory;
FirebaseStorage filesStorage;
String userUUID;
List<ResumeFileUpload> pendingFileUploads;
private SharedPreferences sharedPreferences;
private SharedPreferences.Editor sharedPrefEditor;
private SOTWFormatter sotwFormatter;
#Override
public void onCreate() {
super.onCreate();
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
filesStorage = FirebaseStorage.getInstance();
pendingFileUploads = new ArrayList<>();
sharedPreferences = this.getSharedPreferences(PREFS_TAG, Context.MODE_PRIVATE);
sharedPrefEditor = sharedPreferences.edit();
sotwFormatter = new SOTWFormatter(this);
String timeStamp = sdfForDir.format(new Date());
currentDataDirectory = "RBD_" + timeStamp;
locationDirectory = new File(getExternalFilesDir(null), currentDataDirectory);
if (!locationDirectory.exists())
locationDirectory.mkdir();
}
#RequiresApi(api = Build.VERSION_CODES.O)
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//userUUID = intent.getStringExtra("userUUID");
userUUID = sharedPreferences.getString("userUUID", "UNKNOWN");
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
0, 0, this);
}
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent =
PendingIntent.getActivity(this, 0, notificationIntent, 0);
createNotificationChannel();
Notification notification =
new Notification.Builder(this, CHANNEL_ID)
.setContentTitle(getText(R.string.notification_title))
.setContentText(getText(R.string.notification_message))
.setSmallIcon(R.drawable.bump)
.setContentIntent(pendingIntent)
.setTicker(getText(R.string.ticker_text))
.build();
startForeground(ONGOING_NOTIFICATION_ID, notification);
return START_STICKY;
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel serviceChannel = new NotificationChannel(
CHANNEL_ID,
"Location Service Channel",
NotificationManager.IMPORTANCE_DEFAULT
);
NotificationManager manager = getSystemService(NotificationManager.class);
try {
manager.createNotificationChannel(serviceChannel);
} catch (Exception e) {
e.printStackTrace();
}
}
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
super.onDestroy();
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
locationManager.removeUpdates(this);
}
File newFileLoc = writeLocationDataToFile(locationStringBuilder);
pendingFileUploads.add(new ResumeFileUpload(currentDataDirectory,
newFileLoc.getPath()));
uploadToStorage(newFileLoc);
/*if there are no pending files from some previous session, just save the ones
* that just got created*/
if (getPendingFileUploads() == null){
setList("PendingUploads", pendingFileUploads);
}else{
/*if there are pending uploads from some previous session, fetch them,
* update the list of pending uploads with and save for later upload*/
List<ResumeFileUpload> pUploads = getPendingFileUploads();
for (ResumeFileUpload resumeFileUpload: pendingFileUploads){
pUploads.add(resumeFileUpload);
}
setList("PendingUploads", pUploads);
}
}
private List<ResumeFileUpload> getPendingFileUploads(){
List<ResumeFileUpload> pendingUploads = null;
String serializedObject = sharedPreferences.getString("PendingUploads", null);
if (serializedObject != null){
Gson gson = new Gson();
Type type = new TypeToken<List<ResumeFileUpload>>(){}.getType();
pendingUploads = gson.fromJson(serializedObject, type);
}
return pendingUploads;
}
private boolean deleteFile(File file){
try {
Uri uri = Uri.fromFile(file);
File fdelete = new File(uri.getPath());
if (fdelete.exists()) {
if (fdelete.delete()) {
System.out.println("file Deleted :" + uri.getPath());
return true;
} else {
System.out.println("file not Deleted :" + uri.getPath());
return false;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
private File writeLocationDataToFile(StringBuilder data) {
String fileName = "Location.csv";
String colNamesLoc = "Timestamp,Latitude,Longitude,Accuracy,DirectionOfMotion,Speed\n";
File newFile = new File(locationDirectory, fileName);
try {
FileWriter fileWriter = new FileWriter(newFile);
fileWriter.append(colNamesLoc);
fileWriter.append(data.toString());
fileWriter.flush();
fileWriter.close();
Toast.makeText(this, "Saved To " + getExternalFilesDir(null)
+ "/" + fileName, Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
}
return newFile;
}
private void uploadToStorage(final File newFile){
Uri uri = Uri.fromFile(new File(newFile.getPath()));
StorageReference storageReference = filesStorage.getReference()
.child(userUUID + "/" + currentDataDirectory + "/" +
uri.getLastPathSegment());
UploadTask uploadTask = storageReference.putFile(uri);
uploadTask.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception exception) {
Toast.makeText(LocationService.this,
newFile.getName() + " Upload Failed!", Toast.LENGTH_SHORT).show();
}
}).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
deleteFile(newFile);
Toast.makeText(LocationService.this,
newFile.getName() + " Upload Successful!", Toast.LENGTH_SHORT).show();
}
});
}
/*Location Listener*/
#Override
public void onLocationChanged(Location location) {
if (location != null) {
String lat = coordinatesFormat.format(location.getLatitude());
String lng = coordinatesFormat.format(location.getLongitude());
String bearing = "0.0";
if (location.getBearing() != 0.0)
bearing = String.valueOf(sotwFormatter.format(location.getBearing()));
int speed = (int) location.getSpeed();
String currentSpeed = String.valueOf(speed * 3.6f) + " KM/h";
String accuracy = "0.0";
if (location.getAccuracy() != 0.0)
accuracy = coordinatesFormat.format(location.getAccuracy());
String timeStamp = simpleDateFormat.format(new Date());
String locationData = timeStamp + ", " + lat +
", " + lng + ", " + accuracy + ", " + bearing + ", "
+ currentSpeed;
locationStringBuilder.append(locationData);
locationStringBuilder.append("\n");
}
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
}
/*SharedPreferences code*/
public <T> void setList(String key, List<T> list) {
Gson gson = new Gson();
String json = gson.toJson(list);
set(key, json);
}
public void set(String key, String value) {
sharedPrefEditor.putString(key, value);
sharedPrefEditor.commit();
}
}
I am new to android .I am getting a runtime exception says "Error receiving broadcast Intent ACTION_POWER_DISCONNECTED ".I instantiate my receiver in onCreate() of my activity then I register my receiver in onResume() and unregistered it in onPause() methods.
Actually i want to set text Charging and Not Charging according to the charging mode of my app
package com.example.mrfrag.firebattery;
import android.content.BroadcastReceiver;
import android.content.ContentProvider;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class HomeActivity extends AppCompatActivity{
TextView batteryplus,temp,setting,plug,charging,battery;
private BroadcastReceiver mReceiver;
IntentFilter ifilter =new IntentFilter();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
batteryplus= findViewById(R.id.batteryplus);
temp = findViewById(R.id.temp);
setting= findViewById(R.id.setting);
plug= findViewById(R.id.plug);
charging= findViewById(R.id.charging);
battery= findViewById(R.id.battery);
mReceiver=new PowerConnectionReceiver();
ifilter.addAction(Intent.ACTION_POWER_CONNECTED);
ifilter.addAction(Intent.ACTION_POWER_DISCONNECTED);
ifilter.addAction(Intent.ACTION_BATTERY_CHANGED);
}
#Override
protected void onResume() {
super.onResume();
registerReceiver(mReceiver, ifilter);
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(mReceiver);
}
public class PowerConnectionReceiver extends BroadcastReceiver {
public PowerConnectionReceiver(){
}
#Override
public void onReceive(Context context, Intent batteryStatus) {
int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS,
-1);
boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING
||
status == BatteryManager.BATTERY_STATUS_FULL;
if (isCharging) {
plug.setText("CHARGING");
} else {
plug.setText("NOT CHARGING");
}
int health =
batteryStatus.getIntExtra(BatteryManager.EXTRA_HEALTH,0);
batteryplus.setText(ConvoHealth(health));
String technology =
batteryStatus.getExtras().getString(BatteryManager.EXTRA_TECHNOLOGY);
setting.setText(technology);
float tpr = ((float)
batteryStatus.getIntExtra(BatteryManager.EXTRA_TEMPERATURE,0)) / 10.0f;
temp.setText( String.valueOf(tpr) + "°C / " +
String.valueOf(tpr*1.8+32)+"F"+"\n");
int voltage =
batteryStatus.getIntExtra(BatteryManager.EXTRA_VOLTAGE,0);
charging.setText(voltage+ " mV");
int mah = batteryStatus.getIntExtra(String.valueOf
(BatteryManager.BATTERY_PROPERTY_CAPACITY),0);
battery.setText(mah+ " Mah");
}
}
private String ConvoHealth(int health){
String result;
switch(health){
case BatteryManager.BATTERY_HEALTH_COLD:
result = "COLD";
break;
case BatteryManager.BATTERY_HEALTH_DEAD:
result = "DEAD";
break;
case BatteryManager.BATTERY_HEALTH_GOOD:
result = "GOOD";
break;
case BatteryManager.BATTERY_HEALTH_OVERHEAT:
result = "OVERHEAT";
break;
case BatteryManager.BATTERY_HEALTH_OVER_VOLTAGE:
result = "OVER VOLTAGE";
break;
case BatteryManager.BATTERY_HEALTH_UNKNOWN:
result = "UNKNOWN";
break;
case BatteryManager.BATTERY_HEALTH_UNSPECIFIED_FAILURE:
result = "UNSPECIFIED_FAILURE";
break;
default:
result = "Unknown";
}
return result;
}
}
This is my AndroidManifest.xml file
This is Runtime exception
The reason you are getting this exception is because of following line:
String technology =
batteryStatus.getExtras().getString(BatteryManager.EXTRA_TECHNOLOGY);
setting.setText(technology);
The above line is throwing null pointer. This extra is only available for Intent.ACTION_BATTERY_CHANGED. So either remove it or add condition
if(intent.getAction().equals(Intent.ACTION_BATTERY_CHANGED)){
String technology =
batteryStatus.getExtras().getString(BatteryManager.EXTRA_TECHNOLOGY);
setting.setText(technology);
setting.setText(technology);
}
i'm making a service
which works perfactly well so far,
but everytime the phone restarts, the service is lost,
how do i make the service restart every time the phone shuts off, and turns back on again , (if it was running out of battery, or if user has done a restart)
is there a simple way of making it ?
this is my service >
package com.greenroad.candidate.mywallpaperchanger;
import android.app.Service;
import android.app.WallpaperManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.WindowManager;
import android.widget.Toast;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
/**
* Created by pitsponet on 31/08/2015.
*/
public class myService extends Service {
int oneSecond = 1000;
int oneMinute = oneSecond*60;
int oneHour = oneMinute*60;
int pictureNumberToChoos = 0;
boolean isTimerRunning = false;
int timerDeley = oneHour;
private Timer timer;
private TimerTask timerTask = new TimerTask() {
#Override
public void run() {
//this timer will run again in 10 seconds
Log.d("MyLog", "timer entered ");
//shows a toast saying timer has entered
Handler mainHandler = new Handler(getApplicationContext().getMainLooper());
mainHandler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), "timer listener Entered", Toast.LENGTH_LONG).show();
}
});
//takes picture modifier and updates it to +1 then stores it at var > pictureModifireInt
// Access the default SharedPreferences
SharedPreferences pref = getApplicationContext().getSharedPreferences("myGlobalPrefTable", MODE_PRIVATE);
SharedPreferences.Editor editor = pref.edit();
//open a boolean to tell if the service is activated for the first time it will say false
Integer pictureModifireInt = pref.getInt("pictureModifire", 0);
pictureModifireInt++;
/////holds a list with all the images
int displayPicture = R.drawable.captain;
ArrayList<Integer> pictureNames = new ArrayList<>();
pictureNames.add(R.drawable.captain);
pictureNames.add(R.drawable.flash);
pictureNames.add(R.drawable.superman);
pictureNames.add(R.drawable.thor);
pictureNames.add(R.drawable.wonder);
pictureNames.add(R.drawable.a);
pictureNames.add(R.drawable.b);
pictureNames.add(R.drawable.c);
pictureNames.add(R.drawable.d);
pictureNames.add(R.drawable.e);
pictureNames.add(R.drawable.f);
pictureNames.add(R.drawable.g);
pictureNames.add(R.drawable.h);
pictureNames.add(R.drawable.i);
pictureNames.add(R.drawable.j);
pictureNames.add(R.drawable.k);
pictureNames.add(R.drawable.l);
pictureNames.add(R.drawable.m);
pictureNames.add(R.drawable.n);
pictureNames.add(R.drawable.o);
//logs the stored prefrence and select the correct image at place > picture modifire
Log.d("myLog", "storedPreference: " + pictureModifireInt);
displayPicture = pictureNames.get(pictureModifireInt-1);
if(pictureModifireInt > 19){
// Edit the saved preferences
Log.d("myLog", "putting in pictureModifire : : " + 0);
editor.putInt("pictureModifire", 0); // getting String
editor.commit();
} else {
Log.d("myLog", "putting in pictureModifire : : " + pictureModifireInt);
editor.putInt("pictureModifire", pictureModifireInt); // getting String
editor.commit();
}
///////////////////////////start of wallpaper implemintation
WindowManager wm= (WindowManager) getSystemService(MainActivity.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
Bitmap bmap2 = BitmapFactory.decodeResource(getResources(), displayPicture);
Bitmap bitmap = Bitmap.createScaledBitmap(bmap2, width, height, true);
WallpaperManager wallpaperManager = WallpaperManager.getInstance(getApplicationContext());
try {
wallpaperManager.setBitmap(bitmap);
} catch (IOException e) {
e.printStackTrace();
}
//////////////////////////end of wallpaper implementation
mainHandler = new Handler(getApplicationContext().getMainLooper());
final Integer finalPictureModifireInt = pictureModifireInt-1;
mainHandler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), "wallpaper changed to : "+ finalPictureModifireInt+" and started a new timer", Toast.LENGTH_LONG).show();
}
});
}
};
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
Toast.makeText(getApplicationContext(), "a new service created",
Toast.LENGTH_LONG).show();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("MyLog", "a new service started");
final Handler mainHandler = new Handler(getApplicationContext().getMainLooper());
mainHandler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), "serviceStarterd", Toast.LENGTH_LONG).show();
// Access the default SharedPreferences
SharedPreferences pref = getApplicationContext().getSharedPreferences("myGlobalPrefTable", MODE_PRIVATE);
SharedPreferences.Editor editor = pref.edit();
//open a boolean to tell if the service is activated for the first time it will say false
boolean serviceStateOn = pref.getBoolean("isServiceActivated", false);
if(serviceStateOn == false){
// Edit the saved preferences
Toast.makeText(getApplicationContext(), "a New Timer Started with Delay: "+timerDeley, Toast.LENGTH_LONG).show();
editor.putBoolean("isServiceActivated", true); // getting String
editor.commit();
timer = new Timer();
timer.scheduleAtFixedRate(timerTask, timerDeley, timerDeley);
} else {
Log.d ("myLog", "Service is on so do nothing");
}
}
});
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(getApplicationContext(), "service stoped",
Toast.LENGTH_LONG).show();
}
}
and this is my Manifest >
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.greenroad.candidate.mywallpaperchanger" >
<uses-permission android:name="android.permission.SET_WALLPAPER"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".myService"
android:exported="false"
/>
</application>
</manifest>
THANKX EVERYONE IN ADVANCe ! "_
i wouldn't know how to live without this site lol..
You need to make a receiver which will listen to intent.Boot complete.
And then in on receive(), you can start your service.
You need to add Receiver Class.
Add below permission in AndroidManifest.xml file.
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
Add below statements in Application Tag in AndroidManifest.xml
<receiver android:name=".YourBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter></receiver>
YourBroadcastReceiver.java
package com.test;
public class MyBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent startServiceIntent = new Intent(context, MyService.class);
context.startService(startServiceIntent);
}
}
I am basically working with Android Application , i have requirement to restrict to open others apps while my app is running, Means My app is running it will put some locks on other application while i am accessing the others app, Kind of Application Lock. I am trying but could not find good solution. If any buddy have some idea or link or sample code please share to me.
Basically you want Kiosk Mode .
Try this:
Home button press:
<category android:name="android.intent.category.HOME" /> //add in manifest
What id does: whenever you press the home button, all the applications installed in your phone which have category.HOME category in intent-filter in their AndroidManifest.xml will be listed .
then handle Long press Home Button:
#Override
protected void onPause() {
super.onPause();
ActivityManager activityManager = (ActivityManager) getApplicationContext()
.getSystemService(Context.ACTIVITY_SERVICE);
activityManager.moveTaskToFront(getTaskId(), 0);
}
for this add this line in manifest :
<uses-permission android:name="android.permission.REORDER_TASKS" />
3.handle BackButton :
#Override
public void onBackPressed() {
// Stop user to exit
// super.onBackPressed();
}
You can also try this for Kiosk Mode:
Read this document
import android.app.ActivityManager;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.IBinder;
import android.provider.SyncStateContract;
import android.util.Log;
import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
public class HeartBeat extends Service {
private static final String TAG = HeartBeat.class.getSimpleName();
public Timer TIMER;
// private static Set<AccessGranted> mAccessGrantedList = new HashSet<AccessGranted>();
private Set<String> mLockedApps = new HashSet<String>();
private long lastModified = 0;
private BroadcastReceiver mScreenStateReceiver;
// private BroadcastReceiver mAccessGrantedReceiver;
private File mLockedAppsFile;
ArrayList<String> packagezList;
SharedPreferences sharedPrefs;
Map<String, ?> allEntries;
SharedPreferences sharedPrefsapp;
String prefix;
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
startService(new Intent(this, HeartBeat.class));
Log.i("LocalService", "Received start id " + startId + ": " + intent);
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
if (TIMER == null) {
TIMER = new Timer(true);
TIMER.scheduleAtFixedRate(new LockAppsTimerTask(), 1000, 250);
mScreenStateReceiver = new BroadcastReceiver() {
private boolean screenOff;
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
screenOff = true;
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
screenOff = false;
}
if (screenOff) {
//Log.i(TAG, "Cancel Timer");
TIMER.cancel();
} else {
// Log.i(TAG, "Restart Timer");
TIMER = new Timer(true);
TIMER.scheduleAtFixedRate(new LockAppsTimerTask(), 1000, 250);
}
}
};
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(mScreenStateReceiver, filter);
}
// this.stopSelf();
//startforeground goes here
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
startService(new Intent(this, HeartBeat.class));
}
private class LockAppsTimerTask extends TimerTask {
#Override
public void run() {
sharedPrefs = getApplicationContext().getSharedPreferences(getApplicationContext().getPackageName(), Context.MODE_PRIVATE);
sharedPrefsapp = getApplicationContext().getSharedPreferences("appdb", Context.MODE_PRIVATE);
allEntries= null;
allEntries = sharedPrefsapp.getAll();
Set keySet = allEntries.keySet();
Iterator<String> keySetIter = keySet .iterator();
while (keySetIter.hasNext()) {
String keyEntry= keySetIter.next();
Log.e("Shared Vaues",keyEntry);
}
//prefix = "m";
packagezList= null;
packagezList = new ArrayList<String>();
for (Map.Entry<String, ?> entry : allEntries.entrySet()) {
packagezList.add(entry.getKey());
Log.e("right key: ", entry.getKey().toString() + "right value: " + entry.getValue().toString());
}
/* for (Map.Entry<String, ?> entry : allEntries.entrySet())
{
//Check if the package name starts with the prefix.
if (entry.getKey().startsWith(prefix)) {
//Add JUST the package name (trim off the prefix).
packagezList.add(entry.getKey().substring(prefix.length()));
packagezList.add(entry.getKey());
}
}*/
for(Object object: packagezList){
Log.e("YO!", (String) object);
}
ActivityManager activityManager = (ActivityManager) getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
try {
//List<RecentTaskInfo> recentTasks = activityManager.getRecentTasks(1, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
ActivityManager mActivityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> RunningTask = mActivityManager
.getRunningTasks(1);
ActivityManager.RunningTaskInfo ar = RunningTask.get(0);
String activityOnTop = ar.topActivity.getPackageName();
Log.e("activity on Top", "" + activityOnTop);
Log.e(" My package name", "" + getApplicationContext().getPackageName());
//for (Object data : newArrayList) {
for(Object object: packagezList){
// Provide the packagename(s) of apps here, you want to show password activity
if (!activityOnTop.contains(getApplicationContext().getPackageName()))
// if(!activityOnTop.contains(getApplicationContext().getPackageName()))
{ // you have to make this check even better
Intent i = new Intent(getApplicationContext(), LockScreenActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION);
i.putExtra( "", "");
startActivity(i);
}
}
} catch (Exception e) {
Log.e("Foreground App", e.getMessage(), e);
}
}
}
Following will give me basic wifi information, but I want the hardware information:
WiFiScanReceiver.java
import java.util.List;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.util.Log;
import android.widget.Toast;
public class WiFiScanReceiver extends BroadcastReceiver {
private static final String TAG = "WiFiScanReceiver";
systemInfo systemInfo;
public WiFiScanReceiver(systemInfo systemInfo) {
super();
this.systemInfo = systemInfo;
}
#Override
public void onReceive(Context c, Intent intent) {
List<ScanResult> results = systemInfo.wifi.getScanResults();
ScanResult bestSignal = null;
for (ScanResult result : results) {
if (bestSignal == null
|| WifiManager.compareSignalLevel(bestSignal.level,
result.level) < 0) bestSignal = result;
}
String message = String.format(
"%s networks found. %s is the strongest.", results.size(),
bestSignal.SSID);
Toast.makeText(systemInfo, message, Toast.LENGTH_LONG).show();
Log.d(TAG, "onReceive() message: " + message);
}
}
systemInfo.java
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.List;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager.MemoryInfo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.IntentFilter;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class systemInfo extends Activity implements OnClickListener {
private static final String TAG = "WiFiDemo";
WifiManager wifi;
BroadcastReceiver receiver;
TextView textStatus;
Button buttonScan;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Setup UI
textStatus = (TextView) findViewById(R.id.textStatus);
buttonScan = (Button) findViewById(R.id.buttonScan);
buttonScan.setOnClickListener(this);
// Setup WiFi
wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
// Get WiFi status
WifiInfo info = wifi.getConnectionInfo();
textStatus.append("\n\nWiFi Status: " + info.toString());
// List available networks
List<WifiConfiguration> configs = wifi.getConfiguredNetworks();
for (WifiConfiguration config : configs) {
textStatus.append("\n\n" + config.toString());
}
// Register Broadcast Receiver
if (receiver == null) receiver = new WiFiScanReceiver(this);
registerReceiver(receiver, new IntentFilter(
WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
Log.d(TAG, "onCreate()");
MemoryInfo mi = new MemoryInfo();
ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
activityManager.getMemoryInfo(mi);
long availableMegs = mi.availMem / 1048576L;
System.out.println("availableMegs:::::::::::" + availableMegs);
}
#Override
public void onStop() {
unregisterReceiver(receiver);
}
public void onClick(View view) {
Toast.makeText(this, "On Click Clicked. Toast to that!!!",
Toast.LENGTH_LONG).show();
if (view.getId() == R.id.buttonScan) {
Log.d(TAG, "onClick() wifi.startScan()");
wifi.startScan();
String ab = getInfo();
System.out.println("CPU INFORMATON:::::::::::::\n" + ab);
textStatus.append("CPU INFORMATON:::::::::::::\n" + ab);
}
}
private String getInfo() {
StringBuffer sb = new StringBuffer();
sb.append("abi: ").append(Build.CPU_ABI).append("\n");
if (new File("/proc/cpuinfo").exists()) {
try {
BufferedReader br = new BufferedReader(new FileReader(new File(
"/proc/cpuinfo")));
String aLine;
while ((aLine = br.readLine()) != null) {
sb.append(aLine + "\n");
}
if (br != null) {
br.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return sb.toString();
}
}
permissions are
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
This gives me basic wifi information .But I want the hardware information ..
One important difference is the CPU architecture. Although almost all Android devices use ARM CPU, it comes with different versions, including armv5, armv5te, armv6, armv6 with VFP, armv7, armv7 with VFP, armv7 with neon etc.
If your question is how to obtain the hardware information about the WiFi chip, then answer is simple: Android does not provide this kind of data, except of MAC address (which, btw, is not really the hardware information).