Related
I have written an android app which basically allows me to keep track of times and address of GPS coordinates.
I have 3 Lists each corresponding to Lyft, Uber and Other.
But I believe my app starts slowing down my Smart Phone (Samsung Galaxy S7 Edge, with Android O)
can someone look at my code and tell me why is it slowing my smart phone.
My assumption is that, possibly thread synchronization issue.
Attached is my code
1) MainActivity.java
package com.milind.myapp.gpstrackingservice;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Build;
import android.os.PowerManager;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.ActionMode;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity implements AddressListener
{
private static final String TAG = MainActivity.class.getSimpleName();
private PowerManager.WakeLock wakeLock;
private TextView labelAddress;
private TextView multiTextLyft;
private TextView multiTextUber;
private TextView multiTextOther;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
labelAddress = findViewById(R.id.label_address);
multiTextLyft = findViewById(R.id.multi_text_lyft);
multiTextUber = findViewById(R.id.multi_text_uber);
multiTextOther = findViewById(R.id.multi_text_other);
if (MyService.isServiceStarted())
{
MyService.getInstance().load(getSharedPrefs());
refreshAllViews();
}
PowerManager powerManager = (PowerManager) this.getSystemService(Context.POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, "myapp:My Lock");
}
#Override
protected void onStart()
{
super.onStart();
ActivityCompat.requestPermissions(this, new String[]
{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WAKE_LOCK}, 1);
if (!MyService.isServiceStarted())
{
Intent intent = new Intent(this, MyService.class);
intent.setAction(MyService.ACTION_START_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
startForegroundService(intent);
}
else
{
startService(intent);
}
}
}
#Override
public void onWindowFocusChanged(boolean hasFocus)
{
super.onWindowFocusChanged(hasFocus);
if (hasFocus)
{
if (MyService.isServiceStarted())
{
MyService.getInstance().registerAddressListener(this);
}
wakeLock.acquire();
}
else
{
if (MyService.isServiceStarted())
{
MyService.getInstance().unregisterAddressListener(this);
}
wakeLock.release();
}
}
public void onRequestPermissionsResult(int requestCode, String permissions[],
int[] grantResults)
{
switch (requestCode)
{
case 1:
{
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED)
{
}
else
{
// permission denied, boo! Disable the
// functionality that depends on this permission.
}
return;
}
// other 'case' lines to check for other
// permissions this app might request
}
}
#Override
public void onLocationChanged(Location loc)
{
final String address = MyService.getAddress(this, loc);
final CharSequence text = labelAddress.getText();
if (text.toString().equals(address))
{
return;
}
MyService.getInstance().load(getSharedPrefs());
labelAddress.setText(address);
refreshAllViews();
new Tone().play(880);
}
private void refreshAllViews()
{
runOnUiThread(new Runnable()
{
public void run()
{
refereshEditTextLyft();
refereshEditTextUber();
refereshEditTextOther();
}
});
}
private void refereshEditTextLyft()
{
multiTextLyft.setText(MyService.getInstance().getLyftAddresses());
}
private void refereshEditTextUber()
{
multiTextUber.setText(MyService.getInstance().getUberAddresses());
}
private void refereshEditTextOther()
{
multiTextOther.setText(MyService.getInstance().getOtherAddresses());
}
private SharedPreferences getSharedPrefs()
{
return getSharedPreferences("name", MODE_PRIVATE);
}
public void onLyftButtonClicked(View view)
{
MyService.getInstance().addLyftAddress(labelAddress.getText());
new Tone().play(440);
refereshEditTextLyft();
MyService.getInstance().save(getSharedPrefs());
}
public void onUberButtonClicked(View view)
{
MyService.getInstance().addUberAddress(labelAddress.getText());
new Tone().play(440);
refereshEditTextUber();
MyService.getInstance().save(getSharedPrefs());
}
public void onOtherButtonClicked(View view)
{
MyService.getInstance().addOtherAddress(labelAddress.getText());
new Tone().play(440);
refereshEditTextOther();
MyService.getInstance().save(getSharedPrefs());
}
public void onClearButtonClicked(View view)
{
if (MyService.isServiceStarted())
{
SharedPreferences sharedPreferences = getSharedPrefs();
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.clear();
editor.commit();
MyService.getInstance().clear();
refereshEditTextLyft();
refereshEditTextUber();
refereshEditTextOther();
}
}
public void onDelLyftButtonClicked(View view)
{
MyService.getInstance().delLyftEntry();
new Tone().play(440);
refereshEditTextLyft();
MyService.getInstance().save(getSharedPrefs());
}
public void onDelUberButtonClicked(View view)
{
MyService.getInstance().delUberEntry();
new Tone().play(440);
refereshEditTextUber();
MyService.getInstance().save(getSharedPrefs());
}
public void onDelOtherButtonClicked(View view)
{
MyService.getInstance().delOtherEntry();
new Tone().play(440);
refereshEditTextOther();
MyService.getInstance().save(getSharedPrefs());
}
#Override
protected void onRestart()
{
super.onRestart();
}
#Override
public void onActionModeFinished(ActionMode mode)
{
super.onActionModeFinished(mode);
}
#Override
public void onBackPressed()
{
super.onBackPressed();
}
}
2) The MyService.java
package com.milind.myapp.gpstrackingservice;
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.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.provider.Settings;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public class MyService extends Service implements LocationListener
{
private static final String TAG = MyService.class.getSimpleName();
public static final String ACTION_START_SERVICE = "ACTION_START_SERVICE";
public static final String ACTION_STOP_SERVICE = "ACTION_STOP_SERVICE";
public static final String ACTION_UBER = "ACTION_UBER";
public static final String ACTION_LYFT = "ACTION_UBER";
public static final String ACTION_END = "ACTION_END";
public static final String LYFT_PREFIX = "Lyft";
public static final String OTHER_PREFIX = "Other";
public static final String UBER_PREFIX = "Uber";
private static MyService mInstance = null;
private List<AddressListener> listeners = new ArrayList<>();
private List<AddressPoint> lyftAddresses = new ArrayList<>();
private List<AddressPoint> uberAddresses = new ArrayList<>();
private List<AddressPoint> otherAddresses = new ArrayList<>();
private Location mLastLocation;
public MyService()
{
super();
Log.d(TAG, "MyService(): constructor called");
}
public static boolean isServiceStarted()
{
Log.d(TAG, "isServiceStarted()");
return mInstance != null;
}
public static final MyService getInstance()
{
return mInstance;
}
#Override
public IBinder onBind(Intent intent)
{
Log.d(TAG, "onBind(Intent intent)");
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Log.d(TAG, "onStartCommand(Intent, flags, startId) : " + hashCode());
Log.d(TAG, "onStartCommand(...) intent=" + intent + "=" + ", flags=" + flags + ", startId=" + startId);
Log.d(TAG, "onStartCommand(...) isServiceStarted=" + isServiceStarted());
String action = null;
if (intent != null)
{
Log.d(TAG, intent.toString());
action = intent.getAction();
}
else
{
Log.d(TAG, "onStartCommand(...): early return");
return super.onStartCommand(intent, flags, startId);
}
if (isServiceStarted() == false && action == ACTION_START_SERVICE)
{
Log.d(TAG, "onStartCommand(...): Service starting=" + startId);
//startForegroundServivceNotification()
startRunningInForeground();
requestLocationUpdates();
mInstance = this;
Log.d(TAG, "onStartCommand(...): Service started=" + startId);
}
else if (isServiceStarted() == true && action == ACTION_STOP_SERVICE)
{
Log.d(TAG, "onStartCommand(...): Service stopping=" + startId);
stopLocationUpdates();
stopSelf();
Log.d(TAG, "onStartCommand(...): Service stop requested" + startId);
mInstance = null;
}
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy()
{
Log.d(TAG, "onDestroy(): Service destroyed");
super.onDestroy();
mInstance = null;
}
private void stopLocationUpdates()
{
Log.d(TAG, "stopLocationUpdates()");
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationManager.removeUpdates(this);
}
private void requestLocationUpdates()
{
Log.d(TAG, "requestLocationUpdates()");
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
try
{
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 1500, 0, this);
Log.w(TAG, "requestLocationUpdates(): ended gracefully");
}
catch (SecurityException ex)
{
Log.w(TAG, "requestLocationUpdates(): Exception");
ex.printStackTrace();
}
}
#Override
public void onLocationChanged(Location location)
{
Log.v(TAG, "onLocationChanged(Location location): started, location=" + location.toString());
dispatchLocationChange(location);
mLastLocation = location;
Log.v(TAG, "onLocationChanged: completed");
}
private void dispatchLocationChange(Location loc)
{
Log.v(TAG, "dispatchLocationChange(Location)");
for (AddressListener listener : listeners)
{
listener.onLocationChanged(loc);
}
}
public static String getAddress(Context context, Location loc)
{
Log.v(TAG, "getAddress(Location loc) started");
List<Address> addresses;
Geocoder gcd = new Geocoder(context, Locale.getDefault());
try
{
addresses = gcd.getFromLocation(loc.getLatitude(),
loc.getLongitude(), 1);
String strReturnAddress = "";
if (addresses != null && addresses.size() > 0)
{
final Address address = addresses.get(0);
Log.d(TAG, address.toString());
String addressLines = "";
Log.v(TAG, "Locale: " + address.getLocale());
for (int i = 0; i <= address.getMaxAddressLineIndex(); ++i)
{
Log.v(TAG, "AddressLine " + i + ": " + address.getAddressLine(i));
addressLines += address.getAddressLine(i) + ", ";
Log.v(TAG, "addressLines:" + addressLines);
}
String strAddress =
addressLines
;
Log.v(TAG, "strAddress:" + strAddress);
strReturnAddress = strAddress.substring(0, strAddress.length() - 2);
Log.v(TAG, "strReturnAddress:" + strReturnAddress);
}
Log.d(TAG, "getAddress(Location loc) completed with return=" + strReturnAddress);
return strReturnAddress;
}
catch (IOException e)
{
e.printStackTrace();
Log.d(TAG, "Exception", e);
}
Log.d(TAG, "getAddress(Location loc) completed with return=null");
return "";
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras)
{
Log.d(TAG, "onStatusChanged(provider, status, extras): status=" + status + ", extras=" + extras);
}
#Override
public void onProviderEnabled(String provider)
{
Log.d(TAG, "onProviderEnabled(provider) ");
}
#Override
public void onProviderDisabled(String provider)
{
Log.d(TAG, "onProviderDisabled(provider) ");
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
private static void logGetProperties(final String tag, final Object obj)
{
Log.v(tag, "logGetProperties(...)");
Class cls = obj.getClass();
Method[] methods = cls.getMethods();
Log.v(tag, "methods.length = " + methods.length);
for (Method method : methods)
{
String methodName = method.getName();
Log.v(tag, "methodName = " + methodName);
if (methodName.startsWith("get")
&& (method.getParameters() == null || method.getParameters().length == 0)
&& method.getReturnType() != Void.class)
{
try
{
Log.v(tag, methodName + " = " + method.invoke(obj, new Object[0]));
}
catch (Exception ex)
{
Log.e(tag, methodName + " Failed (exception)");
}
}
}
}
public AddressListener registerAddressListener(AddressListener listener)
{
Log.d(TAG, "registerAddressListener(AddressListener)");
if (!listeners.contains(listener))
{
listeners.add(listener);
}
return listener;
}
public AddressListener unregisterAddressListener(AddressListener listener)
{
Log.d(TAG, "unregisterAddressListener(AddressListener)");
if (listeners.contains(listener))
{
listeners.remove(listener);
Log.d(TAG, "unregisterAddressListener(AddressListener): Listener removed");
return listener;
}
Log.d(TAG, "unregisterAddressListener(AddressListener): Listener not found");
return null;
}
public void addLyftAddress(CharSequence text)
{
Log.d(TAG, "addLyftAddress(CharSequence text): text: " + text);
lyftAddresses.add(new AddressPoint(System.currentTimeMillis(), text));
}
public void addUberAddress(CharSequence text)
{
Log.d(TAG, "addUberAddress(CharSequence text): text: " + text);
uberAddresses.add(new AddressPoint(System.currentTimeMillis(), text));
}
public void addOtherAddress(CharSequence text)
{
Log.d(TAG, "addOtherAddress(CharSequence text): text: " + text);
otherAddresses.add(new AddressPoint(System.currentTimeMillis(), text));
}
String getLyftAddresses()
{
return getAddresses(lyftAddresses);
}
String getUberAddresses()
{
return getAddresses(uberAddresses);
}
String getOtherAddresses()
{
return getAddresses(otherAddresses);
}
private String getAddresses(List<AddressPoint> addresses)
{
Log.d(TAG, "getAddresses(List<AddressPoint>)");
String strAddresses = "" + addresses.size() + "\n--------\n";
for (int i = 0; i < addresses.size(); ++i)
{
AddressPoint addresspoint = addresses.get(i);
strAddresses += addresspoint + "\n--------\n";
if ((i % 2) != 0)
{
strAddresses += "\n\n";
}
}
return strAddresses;
}
private void startRunningInForeground()
{
//if more than or equal to 26
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
//if more than 26
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O)
{
String CHANNEL_ONE_ID = "Package.Service";
String CHANNEL_ONE_NAME = "Screen service";
NotificationChannel notificationChannel = null;
notificationChannel = new NotificationChannel(CHANNEL_ONE_ID,
CHANNEL_ONE_NAME, NotificationManager.IMPORTANCE_MIN);
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.RED);
notificationChannel.setShowBadge(true);
notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if (manager != null)
{
manager.createNotificationChannel(notificationChannel);
}
Bitmap icon = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_foreground);
Notification notification = new Notification.Builder(getApplicationContext())
.setChannelId(CHANNEL_ONE_ID)
.setContentTitle("Recording data")
.setContentText("App is running background operations")
.setSmallIcon(R.drawable.ic_launcher_background)
.setLargeIcon(icon)
.build();
Intent notificationIntent = new Intent(getApplicationContext(), MainActivity.class);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
notification.contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent, 0);
startForeground(101, notification);
}
//if version 26
else
{
startForeground(101, updateNotification());
}
}
//if less than version 26
else
{
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle("App")
.setContentText("App is running background operations")
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setOngoing(true).build();
startForeground(101, notification);
}
}
private Notification updateNotification()
{
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
new Intent(this, MainActivity.class), 0);
return new NotificationCompat.Builder(this)
.setContentTitle("Activity log")
.setTicker("Ticker")
.setContentText("app is running background operations")
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentIntent(pendingIntent)
.setOngoing(true).build();
}
public void load(final SharedPreferences lSharedPrefs)
{
Log.w(TAG, "load(SharedPreferences): started");
load(lSharedPrefs, lyftAddresses, LYFT_PREFIX);
load(lSharedPrefs, uberAddresses, UBER_PREFIX);
load(lSharedPrefs, otherAddresses, OTHER_PREFIX);
Log.w(TAG, "load(SharedPreferences): completed");
}
private void load(final SharedPreferences lSharedPrefs, final List<AddressPoint> lAddrPoints, final String lPrefix)
{
Log.w(TAG, "load(SharedPreferences, lAddrPoints, lPrefix)");
lAddrPoints.clear();
final int count = lSharedPrefs.getInt(lPrefix + "Count", lAddrPoints.size());
for (int i = 0; i < count; ++i)
{
String address = lSharedPrefs.getString(lPrefix + "Address" + i, null);
final long time = lSharedPrefs.getLong(lPrefix + "Time" + i, 0);
//if address or time is invalid skip to the next entry
if (address == null || time == 0)
{
continue;
}
final AddressPoint addressPoint = new AddressPoint(time, address);
lAddrPoints.add(addressPoint);
}
}
private void save(final SharedPreferences lSharedPrefs, final List<AddressPoint> lAddrPoints, final String lPrefix)
{
Log.w(TAG, "save(SharedPreferences, lAddrPoints, lPrefix)");
SharedPreferences.Editor editor = lSharedPrefs.edit();
final int count = lAddrPoints.size();
//Save the count
editor.putInt(lPrefix + "Count", count);
for (int i = 0; i < count; ++i)
{
//Save the entry
AddressPoint lAddrPoint = lAddrPoints.get(i);
editor.putLong(lPrefix + "Time" + i, lAddrPoint.getTime());
editor.putString(lPrefix + "Address" + i, (String) lAddrPoint.getAddress());
}
Log.w(TAG, "save(sharedFrefs, List, String): commit");
editor.commit();
}
public void save(final SharedPreferences sharedPreferences)
{
Log.w(TAG, "save(SharedPreferences): started");
Log.w(TAG, "save: lyftAddresses");
save(sharedPreferences, lyftAddresses, LYFT_PREFIX);
Log.w(TAG, "save: uberAddresses");
save(sharedPreferences, uberAddresses, UBER_PREFIX);
Log.w(TAG, "save: otherAddresses");
save(sharedPreferences, otherAddresses, OTHER_PREFIX);
Log.w(TAG, "save(SharedPreferences) completed");
}
public void clear()
{
lyftAddresses.clear();
uberAddresses.clear();
otherAddresses.clear();
}
public void delLyftEntry()
{
if (lyftAddresses.size() > 0)
{
lyftAddresses.remove(lyftAddresses.size() - 1);
}
}
public void delUberEntry()
{
if (uberAddresses.size() > 0)
{
uberAddresses.remove(uberAddresses.size() - 1);
}
}
public void delOtherEntry()
{
if (otherAddresses.size() > 0)
{
otherAddresses.remove(otherAddresses.size() - 1);
}
}
}
3) activity_main.xml
4) AndroidManifest.xml
This (likely) isn't a threading issue, in the normal sense of the word. What's happening is you've got a GeoCoder.getFromLocation() call executing on the main thread. Per the documentation:
The returned values may be obtained by means of a network lookup. ...It may be useful to call this method from a thread separate from your primary UI thread.
That means the method could block for several seconds each time it is called. That's more likely if you're driving through an area of spotty cell coverage. Since the method is called with each location update (roughly every 2 seconds), it's understandable that the UI is hanging.
SUGGESTED FIX
Replace your getAddress() function with an AsyncTask, which moves the getFromLocation() call to a background thread (now your app will truly be multithreaded). Something like this should work:
private class GetFromLocationTask extends AsyncTask<Location, Void, List<Address>> {
protected List<Address> doInBackground(Location... locs) {
return gcd.getFromLocation(locs[ 0 ].getLatitude(), locs[ 0 ].getLongitude(), 1);
}
protected void onProgressUpdate(Void... progress) {}
protected void onPostExecute(List<Address> result) {
//execute the remainder of your getAddress() logic here
}
}
Then, execute it using new GetFromLocationTask().execute(location). Call this instead of getAddress(). You don't need to pass a Context to getAddress(), since Service.this will work just as well (it is a Context).
Bonus hint: Note that onLocationChanged() runs on the UI thread, and so does refreshAllViews(). That means your call to runOnUiThread() is superfluous, and it will just execute the given Runnable synchronously.
I have developed an android application to scan ble devices and have done reading and writing the gatt characteristic when the app is in User Interaction. I want to keep the connection to perticular ble device and want to read-write gatt charecteristic when the app is in foreground and background.Here is my BluetoothLeService class.
public class BluetoothLeService extends Service
{
public static final String ACTION_DATA_AVAILABLE = "com.example.tracker.service.ACTION_DATA_AVAILABLE";
public static final String ACTION_GATT_CONNECTED = "com.example.tracker.service.ACTION_GATT_CONNECTED";
public static final String ACTION_GATT_DISCONNECTED = "com.example.tracker.service.ACTION_GATT_DISCONNECTED";
public static final String ACTION_GATT_RSSI_UPDATE = "com.example.tracker.service.ACTION_GATT_RSSI_UPDATE";
public static final String ACTION_GATT_SERVICES_DISCOVERED = "com.example.tracker.service.ACTION_GATT_SERVICES_DISCOVERED";
public static final String ACTION_GATT_WRITE_FAILED = "com.example.tracker.service.ACTION_GATT_WRITE_FAILED";
protected static final UUID CHARACTERISTIC_UPDATE_NOTIFICATION_DESCRIPTOR_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
public static final String CHARACTERISTIC_UUID = "com.example.tracker.service.CHARACTERISTIC_UUID";
public static final String EXTRA_DATA = "com.example.tracker.service.EXTRA_DATA";
public static final String SIGNAL = "SIGNAL";
private static final String TAG = BluetoothLeService.class.getSimpleName();
private final IBinder mBinder = new LocalBinder();
private BluetoothAdapter mBluetoothAdapter;
private String mBluetoothDeviceAddress;
private BluetoothGatt mBluetoothGatt;
private BluetoothManager mBluetoothManager;
private BluetoothGattCharacteristic mFocusedCharacteristic;
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == 2) {
BluetoothLeService.this.broadcastUpdate(BluetoothLeService.ACTION_GATT_CONNECTED);
Log.i(BluetoothLeService.TAG, "Connected to GATT server.");
Log.i("MyActivity", "Connected to GATT server.");
Log.i("MyActivity", "Attempting to start service discovery:" + BluetoothLeService.this.mBluetoothGatt.discoverServices());
} else if (newState == 0) {
String intentAction = BluetoothLeService.ACTION_GATT_DISCONNECTED;
Log.i("MyActivity", "Disconnected from GATT server.");
BluetoothLeService.this.broadcastUpdate(intentAction);
}
}
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == 0) {
BluetoothLeService.this.broadcastUpdate(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED);
} else {
Log.w("MyActivity", "onServicesDiscovered received: " + status);
}
}
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (status == 0) {
BluetoothLeService.this.broadcastUpdate(BluetoothLeService.ACTION_DATA_AVAILABLE, characteristic);
Log.i("MyActivity", "Characteristic flags " + characteristic.getProperties());
BluetoothLeService.this.mFocusedCharacteristic = characteristic;
}
}
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (status == 0) {
BluetoothLeService.this.broadcastUpdate(BluetoothLeService.ACTION_DATA_AVAILABLE, characteristic);
if ((characteristic.getProperties() & 2) > 0) {
BluetoothLeService.this.readCharacteristic();
Log.i("MyActivity", "Characteristic permits read");
}
Log.i("MyActivity", "Characteristic was written");
return;
}
Log.i("MyActivity", "Failed to write characteristic");
BluetoothLeService.this.broadcastUpdate(BluetoothLeService.ACTION_GATT_WRITE_FAILED);
}
public void onReadRemoteRssi(BluetoothGatt gatt, int Rssi, int status) {
if (status == 0) {
BluetoothLeService.this.broadcastUpdate(BluetoothLeService.ACTION_GATT_RSSI_UPDATE, Rssi);
}
}
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
Log.i("MyActivity", "Characteristic has changed");
BluetoothLeService.this.broadcastUpdate(BluetoothLeService.ACTION_DATA_AVAILABLE, characteristic);
}
};
public class LocalBinder extends Binder {
public BluetoothLeService getService() {
return BluetoothLeService.this;
}
}
private void broadcastUpdate(String action) {
sendBroadcast(new Intent(action));
}
private void broadcastUpdate(String action, int Rssi) {
Intent intent = new Intent(action);
intent.putExtra(EXTRA_DATA, Rssi);
sendBroadcast(intent);
}
private void broadcastUpdate(String action, BluetoothGattCharacteristic characteristic) {
Intent intent = new Intent(action);
byte[] data = characteristic.getValue();
if (data != null && data.length > 0) {
StringBuilder stringBuilder = new StringBuilder(data.length);
int length = data.length;
for (int i = 0; i < length; i++) {
stringBuilder.append(String.format("%02X ", new Object[]{Byte.valueOf(data[i])}));
}
intent.putExtra(EXTRA_DATA, new StringBuilder(String.valueOf(new String(data))).append(" [ ").append(stringBuilder.toString()).toString());
intent.putExtra(CHARACTERISTIC_UUID, characteristic.getUuid().toString());
}
sendBroadcast(intent);
}
public IBinder onBind(Intent intent) {
return this.mBinder;
}
public boolean onUnbind(Intent intent) {
close();
return super.onUnbind(intent);
}
public boolean initialize() {
if (this.mBluetoothManager == null) {
this.mBluetoothManager = (BluetoothManager) getSystemService("bluetooth");
if (this.mBluetoothManager == null) {
Log.e(TAG, "Unable to initialize BluetoothManager.");
return false;
}
}
this.mBluetoothAdapter = this.mBluetoothManager.getAdapter();
if (this.mBluetoothAdapter != null) {
return true;
}
Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
return false;
}
public boolean connect(String address) {
if (this.mBluetoothAdapter == null || address == null) {
Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
return false;
} else if (this.mBluetoothDeviceAddress == null || !address.equals(this.mBluetoothDeviceAddress) || this.mBluetoothGatt == null) {
BluetoothDevice device = this.mBluetoothAdapter.getRemoteDevice(address);
if (device == null) {
Log.w(TAG, "LocalDevice not found. Unable to connect.");
return false;
}
this.mBluetoothGatt = device.connectGatt(this, false, this.mGattCallback);
Log.d(TAG, "Trying to create a new connection.");
this.mBluetoothDeviceAddress = address;
return true;
} else {
Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection.");
if (this.mBluetoothGatt.connect()) {
return true;
}
return false;
}
}
public void disconnect() {
if (this.mBluetoothAdapter == null || this.mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
} else {
this.mBluetoothGatt.disconnect();
}
}
public void readRemoteRssi() {
if (this.mBluetoothAdapter == null || this.mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
} else {
this.mBluetoothGatt.readRemoteRssi();
}
}
public BluetoothGattCharacteristic CurrentCharacteristic() {
return this.mFocusedCharacteristic;
}
public String getCurrentCharacteristicUuid() {
return this.mFocusedCharacteristic.getUuid().toString();
}
public void writeCharacteristic(byte[] c) {
mFocusedCharacteristic.setValue(c);
if (mBluetoothGatt!=null && mFocusedCharacteristic!=null){
mBluetoothGatt.writeCharacteristic(mFocusedCharacteristic);
}
}
public void readCharacteristic() {
Log.i("MyActivity", "Read Characteristic");
this.mBluetoothGatt.readCharacteristic(this.mFocusedCharacteristic);
}
public void notifyCharacteristic() {
Log.i("MyActivity", "Notify Characteristic");
setCharacteristicNotification(this.mFocusedCharacteristic, true);
}
public void setCurrentCharacteristic(BluetoothGattCharacteristic characteristic) {
this.mFocusedCharacteristic = characteristic;
}
public void close() {
if (this.mBluetoothGatt != null) {
this.mBluetoothGatt.close();
this.mBluetoothGatt = null;
}
}
public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
if (this.mBluetoothAdapter == null || this.mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
} else {
this.mBluetoothGatt.readCharacteristic(characteristic);
}
}
public boolean setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enable) {
Log.i("MyActivity", "setCharacteristicNotification");
this.mBluetoothGatt.setCharacteristicNotification(characteristic, enable);
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CHARACTERISTIC_UPDATE_NOTIFICATION_DESCRIPTOR_UUID);
descriptor.setValue(enable ? BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE : new byte[2]);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
SystemClock.sleep(200);
return this.mBluetoothGatt.writeDescriptor(descriptor);
}
public List<BluetoothGattService> getSupportedGattServices() {
if (this.mBluetoothGatt == null) {
return null;
}
return this.mBluetoothGatt.getServices();
}
}
The API is the same regardless if your app is in the foreground or background. The only thing you need to do is to make sure the system doesn't kill the app when it is in the background. To do that, simply have a Foreground Service running somewhere in your app process.
Use service to scan and connect ble devices when application is in background in android.
package com.example.tracker.service;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanSettings;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.support.v4.widget.SwipeRefreshLayout;
import android.util.Log;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SeekBar;
import android.widget.Toast;
import com.google.firebase.auth.FirebaseAuth;
import com.example.tracker.R;
import com.example.tracker.utils.SampleGattAttributes;
import com.example.tracker.utils.SharedPreferencesUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import static com.example.tracker.constant.SharedFreferencesConstant.KEY_SP_MOBILE_NUMBER;
/**
* Created by Jprashant on 12/9/17.
*/
public class BackgroundService extends Service{
private int scanPeriod;
Context context;
String TAG="BackgroundService";
private BluetoothAdapter mBluetoothAdapter;
private boolean mScanning;
private Handler mHandler;
public String[] advDataTypes = new String[256];
ArrayList<BluetoothDevice> bluetoothDeviceArrayList=new ArrayList<>();
ArrayList<BluetoothDevice> bluetoothDeviceArrayListTwo=new ArrayList<>();
private static final int REQUEST_ENABLE_BT = 1;
// Stops scanning after 10 seconds.
private static final long SCAN_PERIOD = 10000;
/*Connect Ble Device*/
String deviceId;
public static String arrayDidOpnSec2;
BluetoothGattService gattService4;
public static ArrayList<BluetoothGattCharacteristic> lastCharacteristic;
// AlertDialog.Builder alertDialog;
private float avgRssi = 0.0f;
// private Dialog dialog;
private BluetoothLeService mBluetoothLeService;
private boolean mConnected = false;
private ArrayList<ArrayList<BluetoothGattCharacteristic>> mGattCharacteristics = new ArrayList();
//service and char uuid
private static final int TRACKER_ON_OFF = 2;
private static final UUID TRACER_TRIPPLE_PRESS_SERVICE=UUID.fromString("edfec62e-9910-0bac-5241-d8bda6932a2f");
private static final UUID TRACKER_TRIPPLE_PRESS_CHAR=UUID.fromString("772ae377-b3d2-4f8e-4042-5481d1e0098c");
private static final UUID IMMEDIATE_ALERT_UUID = UUID.fromString("00001802-0000-1000-8000-00805f9b34fb");
private static final UUID ALERT_LEVEL_UUID = UUID.fromString("00002a06-0000-1000-8000-00805f9b34fb");
private Button btnSMS;
public static String mDeviceName,mDeviceAddress,connectionStatus;
/*-------------------------------------------------------------------------------*/
public static final String PREFS_NAME = "PreferencesFile";
public int deviceCount = 0;
public String[] mData = new String[400];
private Handler mHandler1;
private ListView listItems;
/*--------for > 21--------------*/
private BluetoothLeScanner mLEScanner;
private ScanSettings settings;
private List<ScanFilter> filters;
private BluetoothGatt mGatt;
public BackgroundService() {
}
public BackgroundService(Context context) {
this.context = context;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// getting systems default ringtone
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(),"CALL YOUR METHOD",Toast.LENGTH_LONG).show();
mHandler = new Handler();
// Use this check to determine whether BLE is supported on the device. Then you can
// selectively disable BLE-related features.
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(context, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
}
// Initializes a Bluetooth adapter. For API level 18 and above, get a reference to
// BluetoothAdapter through BluetoothManager.
final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
// Checks if Bluetooth is supported on the device.
if (mBluetoothAdapter == null) {
Toast.makeText(context, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();
return;
}
for (int i = 0; i < 256; i += REQUEST_ENABLE_BT) {
advDataTypes[i] = "Unknown Data Type";
}
advDataTypes[REQUEST_ENABLE_BT] = "Flags";
advDataTypes[2] = "Incomplete List of 16-bit Service Class UUIDs";
advDataTypes[3] = "Complete List of 16-bit Service Class UUIDs";
advDataTypes[4] = "Incomplete List of 32-bit Service Class UUIDs";
advDataTypes[5] = "Complete List of 32-bit Service Class UUIDs";
advDataTypes[6] = "Incomplete List of 128-bit Service Class UUIDs";
advDataTypes[7] = "Complete List of 128-bit Service Class UUIDs";
advDataTypes[8] = "Shortened Local Name";
advDataTypes[9] = "Complete Local Name";
advDataTypes[10] = "Tx Power Level";
advDataTypes[13] = "Class of LocalDevice";
advDataTypes[14] = "Simple Pairing Hash";
advDataTypes[15] = "Simple Pairing Randomizer R";
advDataTypes[16] = "LocalDevice ID";
advDataTypes[17] = "Security Manager Out of Band Flags";
advDataTypes[18] = "Slave Connection Interval Range";
advDataTypes[20] = "List of 16-bit Solicitaion UUIDs";
advDataTypes[21] = "List of 128-bit Solicitaion UUIDs";
advDataTypes[22] = "Service Data";
advDataTypes[23] = "Public Target Address";
advDataTypes[24] = "Random Target Address";
advDataTypes[25] = "Appearance";
advDataTypes[26] = "Advertising Interval";
advDataTypes[61] = "3D Information Data";
advDataTypes[255] = "Manufacturer Specific Data";
scanPeriod = getApplicationContext().getSharedPreferences(PREFS_NAME, 0).getInt("scan_interval", 6000);
scanTrackerDevices();
}
}, 10000);
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
}
public void scanTrackerDevices(){
Log.e(TAG,"scanTrackerDevices");
if (!mBluetoothAdapter.isEnabled()) {
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
}
}
scanLeDevice(true);
}
private void scanLeDevice(final boolean enable) {
bluetoothDeviceArrayList.clear();
if (enable) {
// Stops scanning after a pre-defined scan period.
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
int arraySize=bluetoothDeviceArrayListTwo.size();
Log.e(TAG,"bluetoothDeviceArrayListTwo Size in scan :"+arraySize);
for (int i=0;i<bluetoothDeviceArrayListTwo.size();i++){
BluetoothDevice bluetoothDevice=bluetoothDeviceArrayListTwo.get(i);
Log.e(TAG,"Device Name in scan :"+bluetoothDevice.getName());
Log.e(TAG,"Device Address in scan :"+bluetoothDevice.getAddress());
if (i==0){
mBluetoothLeService.connect(bluetoothDevice.getAddress());
}
}
}
}, scanPeriod);
mScanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {
String d = "";
String rd = "";
String h = "0123456789ABCDEF";
int ln = 0;
int i = 0;
while (i < scanRecord.length) {
int x = scanRecord[i] & 255;
rd = new StringBuilder(String.valueOf(rd)).append(h.substring(x / 16, (x / 16) + REQUEST_ENABLE_BT)).append(h.substring(x % 16, (x % 16) +REQUEST_ENABLE_BT)).toString();
if (i == ln) {
ln = (i + x) + REQUEST_ENABLE_BT;
if (x == 0) {
break;
}
d = new StringBuilder(String.valueOf(d)).append("\r\n Length: ").append(h.substring(x / 16, (x / 16) + REQUEST_ENABLE_BT)).append(h.substring(x % 16, (x % 16) +REQUEST_ENABLE_BT)).toString();
i += REQUEST_ENABLE_BT;
x = scanRecord[i] & 255;
d = new StringBuilder(String.valueOf(d)).append(", Type :").append(h.substring(x / 16, (x / 16) + REQUEST_ENABLE_BT)).append(h.substring(x % 16, (x % 16) + REQUEST_ENABLE_BT)).append(" = ").append(advDataTypes[x]).append(", Value: ").toString();
rd = new StringBuilder(String.valueOf(rd)).append(h.substring(x / 16, (x / 16) + REQUEST_ENABLE_BT)).append(h.substring(x % 16, (x % 16) + REQUEST_ENABLE_BT)).toString();
} else {
d = new StringBuilder(String.valueOf(d)).append(" ").append(h.substring(x / 16, (x / 16) + REQUEST_ENABLE_BT)).append(h.substring(x % 16, (x % 16) +REQUEST_ENABLE_BT)).toString();
}
i += REQUEST_ENABLE_BT;
}
Log.e(TAG,"UUID : "+device.getUuids());
String[] arrayDeviceName=String.valueOf(device.getName()).split(" ");
String deviceName0=arrayDeviceName[0];
bluetoothDeviceArrayListTwo.add(device);
}
};
/*-------------------Connect BLE---------------------------------------------*/
private Handler mHandler2;
public final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent)
{
String action = intent.getAction();
if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action))
{
numberOfRssi = 0;
avgRssi = 0.0f;
mConnected = true;
updateConnectionState(R.string.connected);
mHandler2.postDelayed(startRssi, 300);
Log.e(TAG,"ACTION_GATT_CONNECTED");
}
else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
mConnected = false;
updateConnectionState(R.string.disconnected);
Log.e(TAG,"ACTION_GATT_DISCONNECTED");
} else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
displayGattServicesForDimmer(mBluetoothLeService.getSupportedGattServices());// For dimmer
Log.e(TAG,"ACTION_GATT_SERVICES_DISCOVERED");
} else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
Log.e(TAG,"ACTION_DATA_AVAILABLE");
String unknownServiceString = context.getResources().getString(R.string.unknown_service);
displayDimmerData("<<" + SampleGattAttributes.lookup(intent.getStringExtra(BluetoothLeService.CHARACTERISTIC_UUID), unknownServiceString) + ">> Value: " + intent.getStringExtra(BluetoothLeService.EXTRA_DATA) + "]");
displayDimmer2(intent.getStringExtra(BluetoothLeService.EXTRA_DATA));
} else if (BluetoothLeService.ACTION_GATT_RSSI_UPDATE.equals(action)) {
updateRssi(intent.getIntExtra(BluetoothLeService.EXTRA_DATA, -400));
} else if (BluetoothLeService.ACTION_GATT_WRITE_FAILED.equals(action)) {
Log.e(TAG,"ACTION_GATT_WRITE_FAILED");
}
}
};
/*------------------------------------------------------------------------*/
#Override
public void onCreate() {
super.onCreate();
// -------------------Connect Ble--------------------------------------
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED);
intentFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED);
intentFilter.addAction(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED);
intentFilter.addAction(BluetoothLeService.ACTION_DATA_AVAILABLE);
intentFilter.addAction(BluetoothLeService.ACTION_GATT_RSSI_UPDATE);
intentFilter.addAction(BluetoothLeService.ACTION_GATT_WRITE_FAILED);
Log.e(TAG,"OnResume()");
getApplicationContext().registerReceiver(mGattUpdateReceiver, intentFilter);
getApplicationContext().bindService(new Intent(getApplicationContext(), BluetoothLeService.class), mServiceConnection, 1);
mHandler2=new Handler();
}
private BluetoothGattCharacteristic mNotifyCharacteristic;
private final ServiceConnection mServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName componentName, IBinder service) {
mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService();
if (!mBluetoothLeService.initialize()) {
Log.e(TAG, "Unable to initialize Bluetooth");
}
}
public void onServiceDisconnected(ComponentName componentName) {
mBluetoothLeService = null;
}
};
private boolean notificationActive = true;
private int numberOfRssi = 0;
private Runnable startRssi = new Runnable() {
public void run() {
if (mConnected) {
mBluetoothLeService.readRemoteRssi();
mHandler2.postDelayed(startRssi, 200);
}
}
};
public BluetoothGatt getmGatt() {
return mGatt;
}
//code from DeviceControlActivity
private void updateConnectionState(final int resourceId) {
connectionStatus= String.valueOf(resourceId);
Log.e(TAG,"Resource ID"+resourceId);
}
private void displayDimmerData(String data){
Log.e(TAG,"Display Data :"+data);
}
private void displayDimmer2(String data){
Log.e(TAG,"display Dimmer2"+data);
String sosString = data.substring(0, Math.min(data.length(), 3));
Log.e(TAG,"SOS String :"+sosString);
if (sosString.equals("SOS")){
Intent callIntent = new Intent(Intent.ACTION_CALL);
callIntent.setData(Uri.parse("tel:"+ SharedPreferencesUtils.getStringFromSharedPreferences(KEY_SP_MOBILE_NUMBER,getApplicationContext())));
callIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getApplicationContext().startActivity(callIntent);
}
}
private void updateRssi(int data) {
if (data > -400) {
if (this.numberOfRssi > 10) {
this.avgRssi = ((9.0f * this.avgRssi) + ((float) data)) / 10.0f;
} else {
this.avgRssi = (this.avgRssi + ((float) data)) / 2.0f;
this.numberOfRssi++;
}
connectionStatus="Connected, RSSI:" + data + ", Avg:" + Math.round(this.avgRssi);
}
}
/*-------------------------disaplay gatt service for dimmer----------------------*/
private void displayGattServicesForDimmer(List<BluetoothGattService> gattServices) {
if (gattServices != null) {
String unknownServiceString = getResources().getString(R.string.unknown_service);
String unknownCharaString = getResources().getString(R.string.unknown_characteristic);
ArrayList<HashMap<String, String>> gattServiceData = new ArrayList();
ArrayList<ArrayList<HashMap<String, String>>> gattCharacteristicData = new ArrayList();
this.mGattCharacteristics = new ArrayList();
for (BluetoothGattService gattService : gattServices) {
HashMap<String, String> currentServiceData = new HashMap();
String uuid = gattService.getUuid().toString();
currentServiceData.put("NAME", SampleGattAttributes.lookup(uuid, unknownServiceString));
currentServiceData.put("UUID", uuid);
gattServiceData.add(currentServiceData);
ArrayList<HashMap<String, String>> gattCharacteristicGroupData = new ArrayList();
List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
ArrayList<BluetoothGattCharacteristic> charas = new ArrayList();
for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
charas.add(gattCharacteristic);
HashMap<String, String> currentCharaData = new HashMap();
uuid = gattCharacteristic.getUuid().toString();
currentCharaData.put("NAME", "\t\t\t<<" + SampleGattAttributes.lookup(uuid, unknownCharaString) + ">>");
currentCharaData.put("UUID", "\t\t\tUUID: 0x" + uuid.substring(4, 8) + ", Properties: " + translateProperties(gattCharacteristic.getProperties()));
gattCharacteristicGroupData.add(currentCharaData);
Log.i(TAG,"CUrrent CHARACTERISTIC DATA"+currentCharaData);
Log.i(TAG,"UUID : "+uuid.substring(4, 8));
Log.i(TAG,"Proprties : "+gattCharacteristic.getProperties());
Log.i(TAG,"Translate Proprties : "+translateProperties(gattCharacteristic.getProperties()));
Log.i(TAG,"char list"+gattCharacteristicData.toString());
}
gattService4=gattService;
this.mGattCharacteristics.add(charas);
}
if (mGattCharacteristics.get(3)!=null) {
lastCharacteristic = new ArrayList<>(mGattCharacteristics.get(3));
enableNotifyOfCharcteristicForDimmer(lastCharacteristic);
}
}
}
private String translateProperties(int properties) {
String s = "";
if ((properties & 1) > 0) {
s = new StringBuilder(String.valueOf(s)).append("/Broadcast").toString();
}
if ((properties & 2) > 0) {
s = new StringBuilder(String.valueOf(s)).append("/Read").toString();
}
if ((properties & 4) > 0) {
s = new StringBuilder(String.valueOf(s)).append("/WriteWithoutResponse").toString();
}
if ((properties & 8) > 0) {
s = new StringBuilder(String.valueOf(s)).append("/Write").toString();
}
if ((properties & 16) > 0) {
s = new StringBuilder(String.valueOf(s)).append("/Notify").toString();
}
if ((properties & 32) > 0) {
s = new StringBuilder(String.valueOf(s)).append("/Indicate").toString();
}
if ((properties & 64) > 0) {
s = new StringBuilder(String.valueOf(s)).append("/SignedWrite").toString();
}
if ((properties & 128) > 0) {
s = new StringBuilder(String.valueOf(s)).append("/ExtendedProperties").toString();
}
if (s.length() > 1) {
return s.substring(1);
}
return s;
}
// Enable Characteristic for dimmer
public void enableNotifyOfCharcteristicForDimmer(ArrayList<BluetoothGattCharacteristic> lastCharacteristic){
if(mGattCharacteristics!=null) {
checkCharacteristicPresent(lastCharacteristic.get(0));
mBluetoothLeService.setCharacteristicNotification(lastCharacteristic.get(0), true);
notificationActive = true;
Log.e(TAG,"Characteristic index : "+0+":\nM GATT CHARACTERISTIC AT "+"Service 4 : CHAR"+ 0 +" :" +lastCharacteristic.get(0).toString());
checkCharacteristicPresent(lastCharacteristic.get(1));
mBluetoothLeService.setCharacteristicNotification(lastCharacteristic.get(1), true);
notificationActive = true;
Log.e(TAG,"Characteristic index : "+1+":\nM GATT CHARACTERISTIC AT "+"Service 4 : CHAR"+ 1 +" :" +lastCharacteristic.get(1).toString());
checkCharacteristicPresent(lastCharacteristic.get(2));
mBluetoothLeService.setCharacteristicNotification(lastCharacteristic.get(2), true);
notificationActive = true;
Log.e(TAG,"Characteristic index : "+2+":\nM GATT CHARACTERISTIC AT "+"Service 4 : CHAR"+ 2 +" :" +lastCharacteristic.get(2).toString());
checkCharacteristicPresent(lastCharacteristic.get(3));
mBluetoothLeService.setCharacteristicNotification(lastCharacteristic.get(3), true);
notificationActive = true;
Log.e(TAG,"Characteristic index : "+3+":\nM GATT CHARACTERISTIC AT "+"Service 4 : CHAR"+ 3 +" :" +lastCharacteristic.get(3).toString());
checkCharacteristicPresent(lastCharacteristic.get(4));
mBluetoothLeService.setCharacteristicNotification(lastCharacteristic.get(4), true);
notificationActive = true;
Log.e(TAG,"Characteristic index : "+4+":\nM GATT CHARACTERISTIC AT "+"Service 4 : CHAR"+ 4 +" :" +lastCharacteristic.get(4).toString());
checkCharacteristicPresent(lastCharacteristic.get(5));
mBluetoothLeService.setCharacteristicNotification(lastCharacteristic.get(5), true);
notificationActive = true;
Log.e(TAG,"Characteristic index : "+5+":\nM GATT CHARACTERISTIC AT "+"Service 4 : CHAR"+ 5 +" :" +lastCharacteristic.get(5).toString());
checkCharacteristicPresent(lastCharacteristic.get(2));
mBluetoothLeService.setCharacteristicNotification(lastCharacteristic.get(2), true);
notificationActive = true;
Log.e(TAG,"Characteristic index : "+2+":\nM GATT CHARACTERISTIC AT "+"Service 4 : CHAR"+ 2 +" :" +lastCharacteristic.get(2).toString());
}
}
// Check the type of characteristic i.e READ/WRITE/NOTIFY
public void checkCharacteristicPresent(BluetoothGattCharacteristic characteristic) {
int charaProp = characteristic.getProperties();
Log.e(TAG, "checkCharacteristicPresent Prop : " + charaProp);
mBluetoothLeService.setCurrentCharacteristic(characteristic);
if ((charaProp & 2) > 0) {
Log.e(TAG, "CharProp & 2 : " + charaProp);
mBluetoothLeService.readCharacteristic(characteristic);
}
if ((charaProp & 16) > 0) {
Log.e(TAG, "CharProp & 16 : " + charaProp);
mNotifyCharacteristic = characteristic;
} else {
if (mNotifyCharacteristic != null) {
mBluetoothLeService.setCharacteristicNotification(mNotifyCharacteristic, false);
mNotifyCharacteristic = null;
}
}
if ((charaProp & 8) > 0 || (charaProp & 4) > 0) {
Log.e(TAG, "CharProp & 4 : " + charaProp);
} else {
Log.e(TAG, "Else : " + charaProp);
}
}
}
I saw some questions like this, but none of them solved my problem.
I'm starting a background service through an AlarmManager. Everytime the service starts, it checks if it has been disabled in SharedPreferences and, if not, it reschedule a new instance of itself and goes on, following these alternative paths:
if the user wants to use GPS, it waits for user's position and uses
it to call a REST endpoint;
if the user does not want to use GPS, it uses the position stored in prefs.
The result of the HTTP call (timeout: 30 seconds) is a JSONObject, which generates 0-n notifications (depending on how many "close objects" it finds).
My problem is: notifications, even if canceled by the user (sliding on them or opening them), often reappears, as if they were never shown. It should never happen, because the web service receives a list of excluded object ids that are updated every time.
Here the code:
ScannerService.java
package com.kiulomb.itascanner.service;
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationManager;
import android.media.RingtoneManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.Volley;
import com.kiulomb.itascanner.R;
import com.kiulomb.itascanner.network.HTTPRequestManager;
import com.kiulomb.itascanner.network.HTTPResponseListener;
import com.kiulomb.itascanner.network.URLs;
import com.kiulomb.itascanner.pref.FilterPreferencesManager;
import com.kiulomb.itascanner.pref.NotificationsHistoryManager;
import com.kiulomb.itascanner.pref.PrefConstants;
import com.kiulomb.itascanner.utils.Haversine;
import com.kiulomb.itascanner.utils.MyConfiguration;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;
public class ScannerService extends Service {
private static final String TAG = ScannerService.class.getSimpleName();
private boolean locationFound = false;
private boolean withoutLocation = false;
private LocationManager mLocationManager = null;
private final Timer myTimer = new Timer();
private final long TIMEOUT = 20000;
TimerTask myTask = new TimerTask() {
public void run() {
try {
Log.i(TAG, "Timeout is over, trying to stop service (location found? " + locationFound + ")");
if (!locationFound) {
stopSelf();
}
} catch (Exception e) {
Log.e(TAG, "Could not stop service after time: " + e.getMessage());
}
}
};
private LocationListener[] mLocationListeners = new LocationListener[] {
new LocationListener(LocationManager.GPS_PROVIDER),
new LocationListener(LocationManager.NETWORK_PROVIDER)
};
private boolean alreadySearching = false;
private class LocationListener implements android.location.LocationListener {
Location mLastLocation;
LocationListener(String provider) {
Log.i(TAG, "LocationListener is " + provider);
mLastLocation = new Location(provider);
}
#Override
public void onLocationChanged(final Location location) {
Log.i(TAG, "onLocationChanged: " + location);
if (withoutLocation) {
return;
}
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
boolean isConnected = activeNetwork != null && activeNetwork.isConnectedOrConnecting();
if (location != null) {
if (isConnected) {
mLastLocation.set(location);
locationFound = true;
Log.i(TAG, "already searching? " + alreadySearching);
if (!alreadySearching) {
findClosest(location.getLatitude(), location.getLongitude());
}
alreadySearching = true;
} else {
Log.e(TAG, "no connectivity, ending service");
stopSelf();
}
} else {
Log.e(TAG, "no position, ending service");
stopSelf();
}
}
#Override
public void onProviderDisabled(String provider) {
Log.i(TAG, "onProviderDisabled: " + provider);
}
#Override
public void onProviderEnabled(String provider) {
Log.i(TAG, "onProviderEnabled: " + provider);
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
Log.i(TAG, "onStatusChanged: " + provider);
}
}
private void initializeLocationManager() {
Log.d(TAG, "initializeLocationManager");
if (mLocationManager == null) {
mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
}
}
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand");
// super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
#Override
public void onCreate() {
Log.d(TAG, "onCreate");
SharedPreferences pref = getSharedPreferences(PrefConstants.PREF_APP_FILE, MODE_PRIVATE);
if (pref.getBoolean(PrefConstants.PREF_APP_SERVICE_ENABLED, PrefConstants.PREF_APP_SERVICE_ENABLED_DEFAULT)) {
Intent intent = new Intent(ScannerService.this, ScannerService.class);
PendingIntent pintent = PendingIntent.getService(ScannerService.this, 0, intent, 0);
AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Calendar cal = Calendar.getInstance();
alarm.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis() + 60000, pintent); // or setExact() // TODO custom time
// alarm.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 60000, pintent);
if (!pref.getBoolean(PrefConstants.PREF_APP_SERVICE_CUSTOMCENTER, PrefConstants.PREF_APP_SERVICE_CUSTOMCENTER_DEFAULT)) {
// use GPS
initializeLocationManager();
try {
mLocationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER,
MyConfiguration.LOCATION_INTERVAL,
MyConfiguration.LOCATION_DISTANCE,
mLocationListeners[1]);
} catch (SecurityException ex) {
Log.e(TAG, "fail to request location update, ignore", ex);
} catch (IllegalArgumentException ex) {
Log.e(TAG, "network provider does not exist, " + ex.getMessage());
}
try {
mLocationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
MyConfiguration.LOCATION_INTERVAL,
MyConfiguration.LOCATION_DISTANCE,
mLocationListeners[0]);
} catch (SecurityException ex) {
Log.e(TAG, "fail to request location update, ignore", ex);
} catch (IllegalArgumentException ex) {
Log.e(TAG, "gps provider does not exist " + ex.getMessage());
}
} else {
withoutLocation = true;
// do not use GPS
String[] savedNotifCenter = pref.getString(PrefConstants.PREF_APP_SERVICE_CENTER, PrefConstants.PREF_APP_SERVICE_CENTER_DEFAULT).split(",");
double savedLat = Double.parseDouble(savedNotifCenter[0]);
double savedLng = Double.parseDouble(savedNotifCenter[1]);
locationFound = true; // prevent the service from stopping
findClosest(savedLat, savedLng);
}
} else {
stopSelf();
return;
}
/*if (isForeground(getPackageName())) {
Log.i(getClass().getSimpleName(), "application is in foreground, stopping service");
stopSelf();
return;
}*/
myTimer.schedule(myTask, TIMEOUT);
}
public boolean isForeground(String myPackage) {
ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> runningTaskInfo = manager.getRunningTasks(1);
ComponentName componentInfo = runningTaskInfo.get(0).topActivity;
return componentInfo.getPackageName().equals(myPackage);
}
#Override
public void onDestroy() {
Log.d(TAG, "onDestroy");
super.onDestroy();
if (mLocationManager != null) {
for (LocationListener mLocationListener : mLocationListeners) {
try {
mLocationManager.removeUpdates(mLocationListener);
} catch (SecurityException se) {
Log.e(TAG, "security exception", se);
} catch (Exception ex) {
Log.e(TAG, "fail to remove location listeners, ignore", ex);
}
}
}
}
private void findClosest(final double lat, final double lng) {
new Thread(new Runnable() {
#Override
public void run() {
String url = URLs.buildURL(URLs.NOTIFICATIONS);
url += "?lat=" + lat;
url += "&lng=" + lng;
final SharedPreferences pref = getSharedPreferences(PrefConstants.PREF_APP_FILE, MODE_PRIVATE);
if (pref.contains(PrefConstants.PREF_APP_SERVICE_RADIUS)) {
url += "&radius=" + pref.getInt(PrefConstants.PREF_APP_SERVICE_RADIUS, PrefConstants.PREF_APP_SERVICE_RADIUS_DEFAULT);
}
url += "&limit=" + PrefConstants.PREF_APP_MAP_LIMIT_DEFAULT;
if (pref.contains(PrefConstants.PREF_APP_SERVICE_IV)) {
url += "&iv=" + pref.getInt(PrefConstants.PREF_APP_SERVICE_IV, PrefConstants.PREF_APP_SERVICE_IV_DEFAULT);
}
String exclusionsNumbers = getExcludedNumbersParam();
if (exclusionsNumbers.length() > 0) {
url += "&exNum=" + exclusionsNumbers;
}
final NotificationsHistoryManager notificationsHistoryManager = new NotificationsHistoryManager(ScannerService.this);
final List<Long> excludedIds = notificationsHistoryManager.getAlreadyFoundObjects();
String exclusionsIds = getExcludedIdsParam(excludedIds);
if (exclusionsIds.length() > 0) {
url += "&exId=" + exclusionsIds;
}
/*final long lastId = pref.getLong(PrefConstants.PREF_SERVICE_LAST_ID, 0L);
url += "&li=" + lastId;*/
final Context context = ScannerService.this;
HTTPRequestManager requestManager = new HTTPRequestManager(context, url, true, null, new HTTPResponseListener() {
#Override
public void onSuccess(JSONObject response) {
try {
JSONArray responseArray = response.getJSONArray("objects");
final String foundString = getString(R.string.found);
final String inCityString = getString(R.string.in_city);
final String expiringString = getString(R.string.expiring);
final DateFormat sdf = SimpleDateFormat.getTimeInstance();
final Resources res = getResources();
final String packageName = getPackageName();
final String mapsApiKey = getString(R.string.google_maps_key);
final boolean notifClickAutoCancel = pref.getBoolean(PrefConstants.PREF_APP_SERVICE_NOTIFCANCEL, PrefConstants.PREF_APP_SERVICE_NOTIFCANCEL_DEFAULT);
final boolean notifExpiredAutoCancel = pref.getBoolean(PrefConstants.PREF_APP_SERVICE_NOTIFCANCELEXPIRED, PrefConstants.PREF_APP_SERVICE_NOTIFCANCELEXPIRED_DEFAULT);
final boolean mapPicture = pref.getBoolean(PrefConstants.PREF_APP_SERVICE_MAPPICTURE, PrefConstants.PREF_APP_SERVICE_MAPPICTURE_DEFAULT);
final Locale defaultLocale = Locale.getDefault();
Calendar calendar = Calendar.getInstance();
// long maxId = lastId;
for (int i = 0; i < responseArray.length(); i++) {
try {
final MyEntity p = MyEntity.fromJSONLight(responseArray.getJSONObject(i));
// it should never happen, but notifications are shown many times :/
if (!excludedIds.contains(p.getId())) {
excludedIds.add(p.getId());
// maxId = Math.max(p.getId(), maxId);
final double iv = p.getIV();
final long expirationFixed = (p.getDisappearTime() - System.currentTimeMillis() - 2000);
final Calendar expirationTime = (Calendar) calendar.clone();
// now.add(Calendar.SECOND, (int) ((p.getDisappearTime() - System.currentTimeMillis() / 1000) - 2));
expirationTime.setTimeInMillis(expirationTime.getTimeInMillis() + expirationFixed);
final int distance = (int) Math.round(1000 * Haversine.distance(lat, lng, p.getLatitude(), p.getLongitude()));
String cityName = null;
Geocoder gcd = new Geocoder(context, defaultLocale);
List<Address> addresses = gcd.getFromLocation(p.getLatitude(), p.getLongitude(), 1);
if (addresses.size() > 0) {
cityName = addresses.get(0).getLocality();
}
final String cityNameParam = cityName;
new Thread(new Runnable() {
#Override
public void run() {
sendNotification((int) (p.getId()),
foundString + " " + p.getName() + (iv > 0 ? " " + iv + "%" : "") + (cityNameParam != null ? " " + inCityString + " " + cityNameParam : ""),
expiringString + " " + sdf.format(expirationTime.getTime()) + " - " + distance + "m" + (movesStringParam != null ? " (" + movesStringParam + ")" : ""),
p,
res,
packageName,
notifClickAutoCancel,
notifExpiredAutoCancel,
expirationFixed,
mapsApiKey,
mapPicture);
}
}).start();
}
} catch (Exception e) {
Log.e(TAG, "error", e);
}
}
notificationsHistoryManager.saveAlreadyFoundObjects(excludedIds);
stopSelf();
} catch (Exception e) {
Log.e(TAG, "error in reading JSONArray", e);
stopSelf();
}
}
#Override
public void onError(int errorCode) {
stopSelf();
}
});
RequestQueue requestQueue = Volley.newRequestQueue(context);
requestQueue.add(requestManager);
}
}).start();
}
private String getExcludedNumbersParam() {
String exclusionsNumbers = "";
List<Integer> excludedNumbers = new FilterPreferencesManager(ScannerService.this).getNotificationsExcludedNumbers();
int sizeNumbers = excludedNumbers.size();
for (int i = 0; i < sizeNumbers; i++) {
exclusionsNumbers += excludedNumbers.get(i);
if (i < sizeNumbers - 1) {
exclusionsNumbers += ",";
}
}
return exclusionsNumbers;
}
private String getExcludedIdsParam(List<Long> excludedIds) {
String exclusionsIds = "";
int sizeIds = excludedIds.size();
for (int i = 0; i < sizeIds; i++) {
exclusionsIds += excludedIds.get(i);
if (i < sizeIds - 1) {
exclusionsIds += ",";
}
}
return exclusionsIds;
}
private Locale locale = Locale.getDefault();
private void sendNotification(final int notificationId,
final String title,
final String message,
final MyEntity entity,
final Resources res,
final String packageName,
final boolean autoClickCancel,
final boolean autoExpiredCancel,
final long expirationFromNow,
final String mapsApiKey,
final boolean mapPicture) {
final double entityLat = entity.getLatitude();
final double entityLng = entity.getLongitude();
Intent mapIntent = null;
try {
String urlAddress = "http://maps.google.com/maps?q=" + entityLat + "," + entityLng;
mapIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(urlAddress));
} catch (Exception e) {
Log.e(TAG, "error in notification intent preparation", e);
}
PendingIntent pendingIntent = PendingIntent.getActivity(ScannerService.this, 0, mapIntent, PendingIntent.FLAG_CANCEL_CURRENT);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
int drawable = res.getIdentifier("entity" + String.format(locale, "%04d", entity.getNumber()) + "big", "drawable", packageName);
final NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(ScannerService.this)
.setSmallIcon(drawable)
.setContentTitle(title)
.setContentText(message)
.setAutoCancel(autoClickCancel)
.setSound(defaultSoundUri)
.setPriority(Notification.PRIORITY_HIGH)
.setLights(ContextCompat.getColor(ScannerService.this, R.color.colorPrimary), 500, 2000);
if (mapPicture) {
String imageUrl = "https://maps.googleapis.com/maps/api/staticmap"
+ "?center=" + entityLat + "," + entityLng
+ "&zoom=14"
+ "&scale=false"
+ "&size=450x275"
+ "&maptype=roadmap"
+ "&key=" + mapsApiKey
+ "&format=jpg"
+ "&visual_refresh=true";
Log.i(getClass().getSimpleName(), "generated url for notification image: " + imageUrl);
Bitmap bmURL = getBitmapFromURL(imageUrl);
if (bmURL != null) {
notificationBuilder.setStyle(new NotificationCompat.BigPictureStyle().bigPicture(bmURL));
}
}
if (mapIntent != null) {
notificationBuilder.setContentIntent(pendingIntent);
}
if (autoExpiredCancel) {
Log.i(getClass().getSimpleName(), "setting notification timer for expiration, id: " + notificationId + ", expiring in " + expirationFromNow + "ms");
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
Log.i(getClass().getSimpleName(), "canceling notification expired, id: " + notificationId);
notificationManager.cancel(notificationId);
}
}, expirationFromNow);
}
}
// }
private Bitmap getBitmapFromURL(String strURL) {
try {
URL url = new URL(strURL);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
return BitmapFactory.decodeStream(input);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
Notifications history manager
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class NotificationsHistoryManager {
private final static String PREF_FILE = "nh";
private final static String PREF_FOUND_KEY = "f";
private SharedPreferences pref;
public NotificationsHistoryManager(Context context) {
pref = context.getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE);
}
public void saveAlreadyFoundObjects(List<Long> found) {
Set<String> idsString = new HashSet<>();
int size = found.size();
for (int i = Math.max(0, size - 200); i < size; i++) {
long f = found.get(i);
idsString.add(f + "");
}
pref.edit().putStringSet(PREF_FOUND_KEY, idsString).apply();
}
public List<Long> getAlreadyFoundObjects() {
List<Long> excluded = new ArrayList<>();
for (String id : pref.getStringSet(PREF_FOUND_KEY, new HashSet<String>())) {
try {
excluded.add(Long.parseLong(id));
} catch (Exception e) {
Log.e(getClass().getSimpleName(), "error in parsing string '" + id + "' to long id: " + e.getMessage());
}
}
return excluded;
}
public void clean() {
pref.edit().clear().apply();
}
}
Note: when MainActivity is started, it checks if an instance of the service is running and, if not, it schedules a new one with an AlarmManager. I thought it was the cause of the problem, but the service, as you see, checks every time what has already been notified and skip it.
I tried changing START_STICKY to NOT_STICKY, using preferences to handle duplicate IDs, synchronizing operations... I don't know what else to try. Please, help me :) If you need any more details, just ask.
Thank you!
To share what I found... I understood what the problem is.
Take a look at NotificationsHistoryManager: it uses, to save the list of found object, a Set (the only "list" object type available in SharedPreferences), saving only the last 200 objects found (old ones expires, so it is meaningless to keep them).
THE PROBLEM IS: SET ARE NOT ORDERED LIST. The 200 objects I save are not the LAST added, because when I read them from pref (getAlreadyFoundObjects()) they are written in a set, "randomly" ordered.
I had to change the way I stored them, creating a custom string (comma separated values), to be sure they are saved in the order I want.
Hope it helps someone.
Hey guys ive been working on a project to create a type of wifi hot spot manager, so that it records the connected devices with mac address, ip address and other information. However i can't seem to work out as to why when i press get Clients from screen it doesn't gather any data of whos connected. I have compiled the file to an APK to test on my phone seeing as wifi functionality does not work on the emulator in android studio.
Credit for the code goes to:
1) Android 2.3 wifi hotspot API
2) https://www.whitebyte.info/android/android-wifi-hotspot-manager-class
package com.example.gavin.wifiattendance;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.nfc.Tag;
import android.os.AsyncTask;
import android.util.Log;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import java.util.logging.LogRecord;
import android.os.Handler;
/**
* Created by Gavins on 05/03/2015.
*/
public class AccessPoint extends Activity {
private static int constant = 0;
private Context context;
private static int WIFI_STATE_UNKNOWN = -1;
private static int WIFI_STATE_DISABLING = 0;
private static int WIFI_STATE_DISABLED = 1;
public static int WIFI_STATE_ENABLING = 2;
public static int WIFI_STATE_ENABLED = 3;
private static int WIFI_STATE_FAILED = 4;
final static String[] WIFI_STATE_TEXTSTATE = new String[]{
"DISABLING","DISABLED","ENABLING","ENABLED","FAILED"
};
private WifiManager wifi;
private String TAG = "WifiAP";
private int stateWifi = -1;
private boolean alwaysEnabledWifi = true;
//enable or disable the wifi
public void toggleWifiAP(WifiManager wifiHandler, Context context){
if (wifi == null){
wifi = wifiHandler;
}
boolean wifiApIsOn = getWifiApState() == WIFI_STATE_ENABLED || getWifiApState()==WIFI_STATE_ENABLING;
new SetWifiApTask(!wifiApIsOn, false, context).execute();
}
private int setWifiApEnabled(boolean enabled){
Log.d(TAG, "Set wifi enabled called" + enabled);
WifiConfiguration config = new WifiConfiguration();
config.SSID = "Attend Lecture";
config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
//remember wireless state
if (enabled && stateWifi == -1){
stateWifi = wifi.getWifiState();
}
//disable the wireless
if (enabled && wifi.getConnectionInfo() !=null){
Log.d(TAG, "disable wifi: calling");
wifi.setWifiEnabled(false);
int loopMax = 10;
while (loopMax > 0 && wifi.getWifiState() != WifiManager.WIFI_STATE_DISABLED){
Log.d(TAG, "Disable Wifi: Waiting, pass:" + (10-loopMax));
try{
Thread.sleep(500);
loopMax--;
}catch (Exception e){
e.printStackTrace();
}
}
Log.d(TAG, "Disabling wifi is done, pass: " + (10-loopMax));
}
//enable and disable wifi AP
int state = WIFI_STATE_UNKNOWN;
try {
Log.d(TAG, (enabled?"enabling":"Disabling")+"wifi ap: calling");
wifi.setWifiEnabled(false);
Method method1 = wifi.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);
method1.invoke(wifi, config, enabled);
Method method2 = wifi.getClass().getMethod("getWifiState");
state = (Integer)method2.invoke(wifi);
}catch (Exception e){
//Log.e(WIFI_SERVICE, e.getMessage());
}
//Use thread while processing occurs
if (!enabled){
int loopMax = 10;
while (loopMax>0 && (getWifiApState()==WIFI_STATE_DISABLING || getWifiApState()==WIFI_STATE_ENABLED || getWifiApState()==WIFI_STATE_FAILED)){
Log.d(TAG, (enabled?"enabling": "disabling")+ "wifi AP: waiting, pass:" + (10-loopMax));
try {
Thread.sleep(500);
loopMax--;
}catch (Exception e){
}
}
Log.d(TAG, (enabled?"enabling":"disabling")+" Wifi ap: done, pass: " + (10-loopMax));
//enable the wifi
if (stateWifi==WifiManager.WIFI_STATE_ENABLED || stateWifi==WifiManager.WIFI_STATE_ENABLING || stateWifi==WifiManager.WIFI_STATE_UNKNOWN || alwaysEnabledWifi){
Log.d(TAG, "enable wifi: Calling");
wifi.setWifiEnabled(true);
//this way it doesnt hold things up and waits for it to get enabled
}
stateWifi = -1;
}else if (enabled){
int loopMax = 10;
while (loopMax>0 && (getWifiApState()==WIFI_STATE_ENABLING || getWifiApState()==WIFI_STATE_DISABLED || getWifiApState()==WIFI_STATE_FAILED)){
Log.d(TAG, (enabled?"Enabling": "disabling") + "wifi ap: waiting, pass: " + (10-loopMax));
try{
Thread.sleep(500);
loopMax--;
}catch (Exception e){
}
}
Log.d(TAG, (enabled?"Enabling": "disabling")+ "wifi ap: done, pass: " + (10-loopMax));
}
return state;
}
//Get the wifi AP state
public int getWifiApState(){
int state = WIFI_STATE_UNKNOWN;
try {
Method method2 = wifi.getClass().getMethod("getWifiApState");
state = (Integer) method2.invoke(wifi);
}catch (Exception e){
}
if (state>=10){
constant=10;
}
WIFI_STATE_DISABLING = 0+constant;
WIFI_STATE_DISABLED = 1+constant;
WIFI_STATE_ENABLING = 2+constant;
WIFI_STATE_ENABLED = 3+constant;
WIFI_STATE_FAILED = 4+constant;
Log.d(TAG, "getWifiApState " + (state==-1?"UNKNOWN":WIFI_STATE_TEXTSTATE[state-constant]));
return state;
}
class SetWifiApTask extends AsyncTask<Void, Void, Void>{
boolean mMode;
boolean mFinish;
ProgressDialog pDialog;
public SetWifiApTask(boolean mode, boolean finish, Context context){
mMode = mode;
mFinish = finish;
pDialog = new ProgressDialog(context);
}
#Override
protected void onPreExecute(){
super.onPreExecute();
pDialog.setTitle("Turning on Access Point " + (mMode?"On":"Off" + "..."));
pDialog.setMessage("Please wait a moment...");
pDialog.show();
}
#Override
protected void onPostExecute(Void aVoid){
super.onPostExecute(aVoid);
try {
pDialog.dismiss();
MainActivity.updateStatusDisplay();
}catch (IllegalArgumentException e){
};
if (mFinish){
finish();
}
}
#Override
protected Void doInBackground(Void... params) {
setWifiApEnabled(mMode);
return null;
}
}
//get the list connected to the wifi hotspot
public void getClientList(boolean onlyReachable, FinishScanListener finishListener){
getClientList(onlyReachable, 300, finishListener);
}
public void getClientList(final boolean onlyReachable, final int reachableTimeout, final FinishScanListener finishListener){
Runnable runnable = new Runnable() {
#Override
public void run() {
BufferedReader br = null;
final ArrayList<ClientScanResult> result = new ArrayList<>();
try {
br = new BufferedReader(new FileReader("/proc/net/arp"));
String line;
while ((line = br.readLine()) != null){
String[] splitted = line.split(" +");
if ((splitted !=null) && (splitted.length >=4)){
String mac = splitted[3];
if (mac.matches("..:..:..:..:..:..")){
boolean isReachable = InetAddress.getByName(splitted[0]).isReachable(reachableTimeout);
if (!onlyReachable || isReachable){
result.add(new ClientScanResult(splitted[0], splitted[3], splitted[5], isReachable));
}
}
}
}
}catch (Exception e){
Log.e(this.getClass().toString(), e.toString());
}finally {
try {
br.close();
}catch (IOException e){
Log.e(this.getClass().toString(), e.getMessage());
}
}
//Get handler that will be used to post to main thread
Handler mainHandler = new Handler(context.getMainLooper());
Runnable myRunnable = new Runnable() {
#Override
public void run() {
finishListener.onFinishScan(result);
}
};
mainHandler.post(myRunnable);
}
};
Thread myThread = new Thread(runnable);
myThread.start();
}
}
and here is the main activity file:
package com.example.gavin.wifiattendance;
import android.app.Activity;
import android.content.Context;
import android.net.wifi.WifiManager;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.TextView;
import com.example.gavin.wifiattendance.AccessPoint;
import java.util.ArrayList;
public class MainActivity extends ActionBarActivity{
boolean wasApEnabled = false;
static AccessPoint wifiAP;
private WifiManager wifi;
static Button apButton;
static TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
apButton = (Button) findViewById(R.id.toggleBtn);
textView = (TextView) findViewById(R.id.wifiClients);
wifiAP = new AccessPoint();
wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
scan();
apButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
wifiAP.toggleWifiAP(wifi, MainActivity.this);
}
});
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD|WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON|WindowManager.LayoutParams.FLAG_DIM_BEHIND);
}
public void scan(){
wifiAP.getClientList(false, new FinishScanListener() {
#Override
public void onFinishScan(final ArrayList<ClientScanResult> clients) {
textView.setText("WifiApState:" + wifiAP.getWifiApState()+ "\n\n");
textView.append("Clients: \n");
for (ClientScanResult clientScanResult : clients){
textView.append("====================\n");
textView.append("ipAddress: " + clientScanResult.getIpAddress() + "\n");
textView.append("Device: " + clientScanResult.getDevice() + "\n");
textView.append("macAddress: " + clientScanResult.getMacAddress() + "\n");
textView.append("isReachable: " + clientScanResult.isReachable() + "\n");
}
}
});
}
#Override
public void onResume() {
super.onResume();
if (wasApEnabled) {
if (wifiAP.getWifiApState() != wifiAP.WIFI_STATE_ENABLED && wifiAP.getWifiApState() != wifiAP.WIFI_STATE_ENABLING) {
wifiAP.toggleWifiAP(wifi, MainActivity.this);
}
}
updateStatusDisplay();
}
#Override
public void onPause() {
super.onPause();
boolean wifiApIsOn = wifiAP.getWifiApState()==wifiAP.WIFI_STATE_ENABLED || wifiAP.getWifiApState()==wifiAP.WIFI_STATE_ENABLING;
if (wifiApIsOn){
wasApEnabled = true;
wifiAP.toggleWifiAP(wifi, MainActivity.this);
}else {
wasApEnabled = false;
}
updateStatusDisplay();
}
public static void updateStatusDisplay(){
if (wifiAP.getWifiApState()==wifiAP.WIFI_STATE_ENABLED || wifiAP.getWifiApState()==wifiAP.WIFI_STATE_ENABLING){
apButton.setText("Turn Off");
}else {
apButton.setText("Turn on");
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0,0,0, "Get Clients");
return super.onCreateOptionsMenu(menu);
}
public boolean onOptionsItemSelected(int featureId, MenuItem item) {
switch (item.getItemId()){
case 0:
scan();
break;
}
return super.onMenuItemSelected(featureId, item);
}
}
Edit: commented out the main looper made it work but after taking out the comments, the application now crashes on launch
http://gyazo.com/fa068fd1fce3f27f43185c0cd12568c1
I am trying to print the bill through bluetooth using the following code,
when I run the app, first time its getting printed, but when I retry its not getting printed.
package com.sel.bluetooth;
import java.io.OutputStream;
import java.lang.reflect.Method;
import android.app.Activity;
import android.app.Dialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
public class BluetoothPrint extends Activity {
BluetoothAdapter mBTAdapter;
BluetoothSocket mBTSocket = null;
Dialog dialogProgress;
String BILL, TRANS_ID;
String PRINTER_MAC_ID;
final String ERROR_MESSAGE = "There has been an error in printing the bill.";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
// BILL = getIntent().getStringExtra("TO_PRINT");
// TRANS_ID = getIntent().getStringExtra("TRANS_ID");
// PRINTER_MAC_ID = getIntent().getStringExtra("MAC_ID");
PRINTER_MAC_ID = "00:1F:B7:02:8F:44";
//PRINTER_MAC_ID = "00:12:F3:0D:A3:E6";
// TRANS_ID="12345678";
BILL = "\nSale Slip No: 12345678" + " " + "04-08-2011\n";
BILL = BILL + "----------------------------------------";
BILL = BILL + "\n\n";
BILL = BILL + "Total Qty:" + " " + "2.0\n";
BILL = BILL + "Total Value:" + " " + "17625.0\n";
BILL = BILL + "-----------------------------------------";
mBTAdapter = BluetoothAdapter.getDefaultAdapter();
dialogProgress = new Dialog(BluetoothPrint.this);
try {
if (mBTAdapter.isDiscovering())
mBTAdapter.cancelDiscovery();
else
mBTAdapter.startDiscovery();
} catch (Exception e) {
Log.e("Class ", "My Exe ", e);
}
System.out.println("BT Searching status :"
+ mBTAdapter.isDiscovering());
if (mBTAdapter == null) {
Toast.makeText(this, "Device has no bluetooth capability",
Toast.LENGTH_LONG).show();
finish();
} else {
if (!mBTAdapter.isEnabled()) {
Intent i = new Intent(
BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(i, 0);
}
// Register the BroadcastReceiver
IntentFilter filter = new IntentFilter(
BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter); // Don't forget to
// unregister during
// onDestroy
dialogProgress.setTitle("Finding printer...");
dialogProgress
.setOnDismissListener(new DialogInterface.OnDismissListener() {
public void onDismiss(DialogInterface dialog) {
dialog.dismiss();
setResult(RESULT_CANCELED);
finish();
}
});
dialogProgress.show();
}
} catch (Exception e) {
Log.e("Class ", "My Exe ", e);
}
}
public void printBillToDevice(final String address) {
new Thread(new Runnable() {
public void run() {
runOnUiThread(new Runnable() {
public void run() {
dialogProgress.setTitle("Connecting...");
dialogProgress.show();
}
});
mBTAdapter.cancelDiscovery();
try {
System.out
.println("**************************#****connecting");
BluetoothDevice mdevice = mBTAdapter
.getRemoteDevice(address);
Method m = mdevice.getClass().getMethod(
"createRfcommSocket", new Class[] { int.class });
mBTSocket = (BluetoothSocket) m.invoke(mdevice, 1);
mBTSocket.connect();
OutputStream os = mBTSocket.getOutputStream();
os.flush();
os.write(BILL.getBytes());
System.out.println(BILL);
//mBTSocket.close();
setResult(RESULT_OK);
finish();
} catch (Exception e) {
Log.e("Class ", "My Exe ", e);
//Toast.makeText(BluetoothPrint.this, ERROR_MESSAGE, Toast.LENGTH_SHORT).show();
e.printStackTrace();
setResult(RESULT_CANCELED);
finish();
}
runOnUiThread(new Runnable() {
public void run() {
try {
dialogProgress.dismiss();
} catch (Exception e) {
Log.e("Class ", "My Exe ", e);
}
}
});
}
}).start();
}
#Override
protected void onDestroy() {
Log.i("Dest ", "Checking Ddest");
super.onDestroy();
try {
if(dialogProgress != null)
dialogProgress.dismiss();
if (mBTAdapter != null)
mBTAdapter.cancelDiscovery();
this.unregisterReceiver(mReceiver);
} catch (Exception e) {
Log.e("Class ", "My Exe ", e);
}
}
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
try {
String action = intent.getAction();
// When discovery finds a device
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// Get the BluetoothDevice object from the Intent
BluetoothDevice device = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
System.out.println("***" + device.getName() + " : "
+ device.getAddress());
if (device.getAddress().equalsIgnoreCase(PRINTER_MAC_ID)) {
mBTAdapter.cancelDiscovery();
dialogProgress.dismiss();
Toast.makeText(BluetoothPrint.this,
device.getName() + " Printing data",
Toast.LENGTH_LONG).show();
printBillToDevice(PRINTER_MAC_ID);
Toast.makeText(BluetoothPrint.this,
device.getName() + " found", Toast.LENGTH_LONG)
.show();
}
}
} catch (Exception e) {
Log.e("Class ", "My Exe ", e);
//Toast.makeText(BluetoothPrint.this, ERROR_MESSAGE, Toast.LENGTH_SHORT).show();
}
}
};
#Override
public void onBackPressed() {
try {
if (mBTAdapter != null)
mBTAdapter.cancelDiscovery();
this.unregisterReceiver(mReceiver);
} catch (Exception e) {
Log.e("Class ", "My Exe ", e);
}
setResult(RESULT_CANCELED);
finish();
}
}
Here is the perfectely working code for blue-tooth printer in android
device_list.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:id="#+id/title_paired_devices"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:text="My Text" android:visibility="gone"
android:background="#666" android:textColor="#fff"
android:paddingLeft="5dip" />
<ListView android:id="#+id/paired_devices"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:stackFromBottom="true" android:layout_weight="1" />
</LinearLayout>
device_name.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:textSize="18sp" android:padding="5dip" />
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content" android:text="#string/hello" />
<Button android:text="Scan" android:id="#+id/Scan"
android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
<Button android:text="Print" android:id="#+id/mPrint"
android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
<Button android:text="Dissable" android:id="#+id/dis"
android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
</LinearLayout>
DeviceListActivity.java
package com.sel.code;
import java.util.Set;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;
public class DeviceListActivity extends Activity
{
protected static final String TAG = "TAG";
private BluetoothAdapter mBluetoothAdapter;
private ArrayAdapter<String> mPairedDevicesArrayAdapter;
#Override
protected void onCreate(Bundle mSavedInstanceState)
{
super.onCreate(mSavedInstanceState);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.device_list);
setResult(Activity.RESULT_CANCELED);
mPairedDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name);
ListView mPairedListView = (ListView) findViewById(R.id.paired_devices);
mPairedListView.setAdapter(mPairedDevicesArrayAdapter);
mPairedListView.setOnItemClickListener(mDeviceClickListener);
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
Set<BluetoothDevice> mPairedDevices = mBluetoothAdapter.getBondedDevices();
if (mPairedDevices.size() > 0)
{
findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE);
for (BluetoothDevice mDevice : mPairedDevices)
{
mPairedDevicesArrayAdapter.add(mDevice.getName() + "\n" + mDevice.getAddress());
}
}
else
{
String mNoDevices = "None Paired";//getResources().getText(R.string.none_paired).toString();
mPairedDevicesArrayAdapter.add(mNoDevices);
}
}
#Override
protected void onDestroy()
{
super.onDestroy();
if (mBluetoothAdapter != null)
{
mBluetoothAdapter.cancelDiscovery();
}
}
private OnItemClickListener mDeviceClickListener = new OnItemClickListener()
{
public void onItemClick(AdapterView<?> mAdapterView, View mView, int mPosition, long mLong)
{
mBluetoothAdapter.cancelDiscovery();
String mDeviceInfo = ((TextView) mView).getText().toString();
String mDeviceAddress = mDeviceInfo.substring(mDeviceInfo.length() - 17);
Log.v(TAG, "Device_Address " + mDeviceAddress);
Bundle mBundle = new Bundle();
mBundle.putString("DeviceAddress", mDeviceAddress);
Intent mBackIntent = new Intent();
mBackIntent.putExtras(mBundle);
setResult(Activity.RESULT_OK, mBackIntent);
finish();
}
};
}
Main.java
package com.sel.code;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.Set;
import java.util.UUID;
import android.app.Activity;
import android.app.ProgressDialog;
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.Message;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.Toast;
public class Main extends Activity implements Runnable {
protected static final String TAG = "TAG";
private static final int REQUEST_CONNECT_DEVICE = 1;
private static final int REQUEST_ENABLE_BT = 2;
Button mScan, mPrint, mDisc;
BluetoothAdapter mBluetoothAdapter;
private UUID applicationUUID = UUID
.fromString("00001101-0000-1000-8000-00805F9B34FB");
private ProgressDialog mBluetoothConnectProgressDialog;
private BluetoothSocket mBluetoothSocket;
BluetoothDevice mBluetoothDevice;
#Override
public void onCreate(Bundle mSavedInstanceState) {
super.onCreate(mSavedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.main);
mScan = (Button) findViewById(R.id.Scan);
mScan.setOnClickListener(new View.OnClickListener() {
public void onClick(View mView) {
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
Toast.makeText(Main.this, "Message1", 2000).show();
} else {
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(
BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent,
REQUEST_ENABLE_BT);
} else {
ListPairedDevices();
Intent connectIntent = new Intent(Main.this,
DeviceListActivity.class);
startActivityForResult(connectIntent,
REQUEST_CONNECT_DEVICE);
}
}
}
});
mPrint = (Button) findViewById(R.id.mPrint);
mPrint.setOnClickListener(new View.OnClickListener() {
public void onClick(View mView) {
Thread t = new Thread() {
public void run() {
try {
OutputStream os = mBluetoothSocket
.getOutputStream();
String BILL = "";
BILL = "\nInvoice No: ABCDEF28060000005" + " "
+ "04-08-2011\n";
BILL = BILL
+ "-----------------------------------------";
BILL = BILL + "\n\n";
BILL = BILL + "Total Qty:" + " " + "2.0\n";
BILL = BILL + "Total Value:" + " "
+ "17625.0\n";
BILL = BILL
+ "-----------------------------------------\n";
os.write(BILL.getBytes());
//This is printer specific code you can comment ==== > Start
// Setting height
int gs = 29;
os.write(intToByteArray(gs));
int h = 104;
os.write(intToByteArray(h));
int n = 162;
os.write(intToByteArray(n));
// Setting Width
int gs_width = 29;
os.write(intToByteArray(gs_width));
int w = 119;
os.write(intToByteArray(w));
int n_width = 2;
os.write(intToByteArray(n_width));
// Print BarCode
int gs1 = 29;
os.write(intToByteArray(gs1));
int k = 107;
os.write(intToByteArray(k));
int m = 73;
os.write(intToByteArray(m));
String barCodeVal = "ASDFC028060000005";// "HELLO12345678912345012";
System.out.println("Barcode Length : "
+ barCodeVal.length());
int n1 = barCodeVal.length();
os.write(intToByteArray(n1));
for (int i = 0; i < barCodeVal.length(); i++) {
os.write((barCodeVal.charAt(i) + "").getBytes());
}
//printer specific code you can comment ==== > End
} catch (Exception e) {
Log.e("Main", "Exe ", e);
}
}
};
t.start();
}
});
mDisc = (Button) findViewById(R.id.dis);
mDisc.setOnClickListener(new View.OnClickListener() {
public void onClick(View mView) {
if (mBluetoothAdapter != null)
mBluetoothAdapter.disable();
}
});
}// onCreate
#Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
try {
if (mBluetoothSocket != null)
mBluetoothSocket.close();
} catch (Exception e) {
Log.e("Tag", "Exe ", e);
}
}
#Override
public void onBackPressed() {
try {
if (mBluetoothSocket != null)
mBluetoothSocket.close();
} catch (Exception e) {
Log.e("Tag", "Exe ", e);
}
setResult(RESULT_CANCELED);
finish();
}
public void onActivityResult(int mRequestCode, int mResultCode,
Intent mDataIntent) {
super.onActivityResult(mRequestCode, mResultCode, mDataIntent);
switch (mRequestCode) {
case REQUEST_CONNECT_DEVICE:
if (mResultCode == Activity.RESULT_OK) {
Bundle mExtra = mDataIntent.getExtras();
String mDeviceAddress = mExtra.getString("DeviceAddress");
Log.v(TAG, "Coming incoming address " + mDeviceAddress);
mBluetoothDevice = mBluetoothAdapter
.getRemoteDevice(mDeviceAddress);
mBluetoothConnectProgressDialog = ProgressDialog.show(this,
"Connecting...", mBluetoothDevice.getName() + " : "
+ mBluetoothDevice.getAddress(), true, false);
Thread mBlutoothConnectThread = new Thread(this);
mBlutoothConnectThread.start();
// pairToDevice(mBluetoothDevice); This method is replaced by
// progress dialog with thread
}
break;
case REQUEST_ENABLE_BT:
if (mResultCode == Activity.RESULT_OK) {
ListPairedDevices();
Intent connectIntent = new Intent(Main.this,
DeviceListActivity.class);
startActivityForResult(connectIntent, REQUEST_CONNECT_DEVICE);
} else {
Toast.makeText(Main.this, "Message", 2000).show();
}
break;
}
}
private void ListPairedDevices() {
Set<BluetoothDevice> mPairedDevices = mBluetoothAdapter
.getBondedDevices();
if (mPairedDevices.size() > 0) {
for (BluetoothDevice mDevice : mPairedDevices) {
Log.v(TAG, "PairedDevices: " + mDevice.getName() + " "
+ mDevice.getAddress());
}
}
}
public void run() {
try {
mBluetoothSocket = mBluetoothDevice
.createRfcommSocketToServiceRecord(applicationUUID);
mBluetoothAdapter.cancelDiscovery();
mBluetoothSocket.connect();
mHandler.sendEmptyMessage(0);
} catch (IOException eConnectException) {
Log.d(TAG, "CouldNotConnectToSocket", eConnectException);
closeSocket(mBluetoothSocket);
return;
}
}
private void closeSocket(BluetoothSocket nOpenSocket) {
try {
nOpenSocket.close();
Log.d(TAG, "SocketClosed");
} catch (IOException ex) {
Log.d(TAG, "CouldNotCloseSocket");
}
}
private Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
mBluetoothConnectProgressDialog.dismiss();
Toast.makeText(Main.this, "DeviceConnected", 5000).show();
}
};
public static byte intToByteArray(int value) {
byte[] b = ByteBuffer.allocate(4).putInt(value).array();
for (int k = 0; k < b.length; k++) {
System.out.println("Selva [" + k + "] = " + "0x"
+ UnicodeFormatter.byteToHex(b[k]));
}
return b[3];
}
public byte[] sel(int val) {
ByteBuffer buffer = ByteBuffer.allocate(2);
buffer.putInt(val);
buffer.flip();
return buffer.array();
}
}
UnicodeFormatter.java
package com.sel.code;
import java.io.*;
public class UnicodeFormatter {
static public String byteToHex(byte b) {
// Returns hex String representation of byte b
char hexDigit[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f' };
char[] array = { hexDigit[(b >> 4) & 0x0f], hexDigit[b & 0x0f] };
return new String(array);
}
static public String charToHex(char c) {
// Returns hex String representation of char c
byte hi = (byte) (c >>> 8);
byte lo = (byte) (c & 0xff);
return byteToHex(hi) + byteToHex(lo);
}
} // class
I've just uncommented //mBTSocket.close();
Then, just before, add:
if (mBTAdapter != null)
mBTAdapter.cancelDiscovery();
and everything goes well!
Also try closing the OutputStream after writing to it, preferably in the finish block using:
os.close();