Migration to BLE Library 2.2.0-alpha05

Getting rid of hungarian notation
This commit is contained in:
Aleksander Nowakowski
2020-01-31 10:23:30 +01:00
parent 38b5bafe62
commit 807f90ccc7
90 changed files with 2837 additions and 3045 deletions

View File

@@ -57,7 +57,7 @@ dependencies {
// Import the BLE Common Library.
// The BLE Common Library depends on BLE Library. It is enough to include the first one.
implementation 'no.nordicsemi.android:ble-common:2.1.1'
implementation 'no.nordicsemi.android:ble-common:2.2.0-alpha05'
// The BLE Common Library may be included from jcenter. If you want to modify the code,
// clone both projects from GitHub and replace the line above with the following
// (and also the according lines in the settings.gradle):

View File

@@ -57,19 +57,23 @@ public class AppHelpFragment extends DialogFragment {
@Override
@NonNull
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final Bundle args = getArguments();
final Bundle args = requireArguments();
final StringBuilder text = new StringBuilder(getString(args.getInt(ARG_TEXT)));
final boolean appendVersion = args.getBoolean(ARG_VERSION);
if (appendVersion) {
try {
final String version = getActivity().getPackageManager().getPackageInfo(getActivity().getPackageName(), 0).versionName;
final String version = requireContext().getPackageManager()
.getPackageInfo(requireContext().getPackageName(), 0).versionName;
text.append(getString(R.string.about_version, version));
} catch (final NameNotFoundException e) {
// do nothing
}
}
return new AlertDialog.Builder(getActivity()).setTitle(R.string.about_title).setMessage(text)
.setPositiveButton(R.string.ok, null).create();
return new AlertDialog.Builder(requireContext())
.setTitle(R.string.about_title)
.setMessage(text)
.setPositiveButton(R.string.ok, null)
.create();
}
}

View File

@@ -61,12 +61,12 @@ public class FeaturesActivity extends AppCompatActivity {
private static final String NRF_CONNECT_CLASS = NRF_CONNECT_PACKAGE + ".DeviceListActivity";
private static final String NRF_CONNECT_MARKET_URI = "market://details?id=no.nordicsemi.android.mcp";
// Extras that can be passed from NFC (see SplashscreenActivity)
// Extras that can be passed from NFC (see SplashScreenActivity)
public static final String EXTRA_APP = "application/vnd.no.nordicsemi.type.app";
public static final String EXTRA_ADDRESS = "application/vnd.no.nordicsemi.type.address";
private DrawerLayout mDrawerLayout;
private ActionBarDrawerToggle mDrawerToggle;
private DrawerLayout drawerLayout;
private ActionBarDrawerToggle drawerToggle;
@Override
protected void onCreate(final Bundle savedInstanceState) {
@@ -80,18 +80,18 @@ public class FeaturesActivity extends AppCompatActivity {
if (!ensureBLEExists())
finish();
final DrawerLayout drawer = mDrawerLayout = findViewById(R.id.drawer_layout);
final DrawerLayout drawer = drawerLayout = findViewById(R.id.drawer_layout);
drawer.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
// Set the drawer toggle as the DrawerListener
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.string.drawer_open, R.string.drawer_close) {
drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.string.drawer_open, R.string.drawer_close) {
@Override
public void onDrawerSlide(final View drawerView, final float slideOffset) {
// Disable the Hamburger icon animation
super.onDrawerSlide(drawerView, 0);
}
};
drawer.addDrawerListener(mDrawerToggle);
drawer.addDrawerListener(drawerToggle);
// setup plug-ins in the drawer
setupPluginsInDrawer(drawer.findViewById(R.id.plugin_container));
@@ -130,23 +130,24 @@ public class FeaturesActivity extends AppCompatActivity {
protected void onPostCreate(final Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// Sync the toggle state after onRestoreInstanceState has occurred.
mDrawerToggle.syncState();
drawerToggle.syncState();
}
@Override
public void onConfigurationChanged(@NonNull final Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mDrawerToggle.onConfigurationChanged(newConfig);
drawerToggle.onConfigurationChanged(newConfig);
}
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
public boolean onOptionsItemSelected(@NonNull final MenuItem item) {
// Pass the event to ActionBarDrawerToggle, if it returns
// true, then it has handled the app icon touch event
if (mDrawerToggle.onOptionsItemSelected(item)) {
if (drawerToggle.onOptionsItemSelected(item)) {
return true;
}
//noinspection SwitchStatementWithTooFewBranches
switch (item.getItemId()) {
case R.id.action_about:
final AppHelpFragment fragment = AppHelpFragment.getInstance(R.string.about_text, true);
@@ -185,7 +186,7 @@ public class FeaturesActivity extends AppCompatActivity {
} catch (final ActivityNotFoundException e) {
Toast.makeText(FeaturesActivity.this, R.string.no_application_play, Toast.LENGTH_SHORT).show();
}
mDrawerLayout.closeDrawers();
drawerLayout.closeDrawers();
});
// look for other plug-ins
@@ -206,7 +207,7 @@ public class FeaturesActivity extends AppCompatActivity {
intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
mDrawerLayout.closeDrawers();
drawerLayout.closeDrawers();
});
container.addView(item);
}

View File

@@ -32,27 +32,27 @@ public class PermissionRationaleFragment extends DialogFragment {
private static final String ARG_PERMISSION = "ARG_PERMISSION";
private static final String ARG_TEXT = "ARG_TEXT";
private PermissionDialogListener mListener;
private PermissionDialogListener listener;
public interface PermissionDialogListener {
void onRequestPermission(final String permission);
}
@Override
public void onAttach(final Context context) {
public void onAttach(@NonNull final Context context) {
super.onAttach(context);
if (context instanceof PermissionDialogListener) {
mListener = (PermissionDialogListener) context;
listener = (PermissionDialogListener) context;
} else {
throw new IllegalArgumentException("The parent activity must impelemnt PermissionDialogListener");
throw new IllegalArgumentException("The parent activity must implement PermissionDialogListener");
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
listener = null;
}
public static PermissionRationaleFragment getInstance(final int aboutResId, final String permission) {
@@ -69,10 +69,10 @@ public class PermissionRationaleFragment extends DialogFragment {
@Override
@NonNull
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final Bundle args = getArguments();
final Bundle args = requireArguments();
final StringBuilder text = new StringBuilder(getString(args.getInt(ARG_TEXT)));
return new AlertDialog.Builder(getActivity()).setTitle(R.string.permission_title).setMessage(text)
return new AlertDialog.Builder(requireContext()).setTitle(R.string.permission_title).setMessage(text)
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.ok, (dialog, which) -> mListener.onRequestPermission(args.getString(ARG_PERMISSION))).create();
.setPositiveButton(R.string.ok, (dialog, which) -> listener.onRequestPermission(args.getString(ARG_PERMISSION))).create();
}
}

View File

@@ -37,27 +37,29 @@ import java.util.Collections;
import java.util.List;
import java.util.Locale;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import no.nordicsemi.android.nrftoolbox.R;
public class AppAdapter extends BaseAdapter {
private static final String CATEGORY = "no.nordicsemi.android.nrftoolbox.LAUNCHER";
private static final String NRF_CONNECT_PACKAGE = "no.nordicsemi.android.mcp";
private final Context mContext;
private final PackageManager mPackageManager;
private final LayoutInflater mInflater;
private final List<ResolveInfo> mApplications;
private final Context context;
private final PackageManager packageManager;
private final LayoutInflater inflater;
private final List<ResolveInfo> applications;
public AppAdapter(final Context context) {
mContext = context;
mInflater = LayoutInflater.from(context);
public AppAdapter(@NonNull final Context context) {
this.context = context;
this.inflater = LayoutInflater.from(context);
// get nRF installed app plugins from package manager
final PackageManager pm = mPackageManager = context.getPackageManager();
final PackageManager pm = packageManager = context.getPackageManager();
final Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(CATEGORY);
final List<ResolveInfo> appList = mApplications = pm.queryIntentActivities(intent, 0);
final List<ResolveInfo> appList = applications = pm.queryIntentActivities(intent, 0);
// TODO remove the following loop after some time, when there will be no more MCP 1.1 at the market.
for (final ResolveInfo info : appList) {
if (NRF_CONNECT_PACKAGE.equals(info.activityInfo.packageName)) {
@@ -70,24 +72,24 @@ public class AppAdapter extends BaseAdapter {
@Override
public int getCount() {
return mApplications.size();
return applications.size();
}
@Override
public Object getItem(int position) {
return mApplications.get(position);
public Object getItem(final int position) {
return applications.get(position);
}
@Override
public long getItemId(int position) {
public long getItemId(final int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
public View getView(final int position, @Nullable final View convertView, @NonNull final ViewGroup parent) {
View view = convertView;
if (view == null) {
view = mInflater.inflate(R.layout.feature_icon, parent, false);
view = inflater.inflate(R.layout.feature_icon, parent, false);
final ViewHolder holder = new ViewHolder();
holder.view = view;
@@ -96,8 +98,8 @@ public class AppAdapter extends BaseAdapter {
view.setTag(holder);
}
final ResolveInfo info = mApplications.get(position);
final PackageManager pm = mPackageManager;
final ResolveInfo info = applications.get(position);
final PackageManager pm = packageManager;
final ViewHolder holder = (ViewHolder) view.getTag();
holder.icon.setImageDrawable(info.loadIcon(pm));
@@ -106,7 +108,7 @@ public class AppAdapter extends BaseAdapter {
final Intent intent = new Intent();
intent.setComponent(new ComponentName(info.activityInfo.packageName, info.activityInfo.name));
intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
mContext.startActivity(intent);
context.startActivity(intent);
});
return view;

View File

@@ -16,6 +16,7 @@
package no.nordicsemi.android.nrftoolbox.app;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.database.Cursor;
import android.os.Bundle;
@@ -133,13 +134,15 @@ import no.nordicsemi.android.nrftoolbox.R;
* @see #setListAdapter
* @see android.widget.ExpandableListView
*/
@SuppressLint("Registered")
@SuppressWarnings("unused")
public class ExpandableListActivity extends AppCompatActivity implements
OnCreateContextMenuListener,
ExpandableListView.OnChildClickListener, ExpandableListView.OnGroupCollapseListener,
ExpandableListView.OnGroupExpandListener {
ExpandableListAdapter mAdapter;
ExpandableListView mList;
boolean mFinishedStart = false;
ExpandableListAdapter adapter;
ExpandableListView list;
boolean finishedStart = false;
/**
* Override this to populate the context menu when an item is long pressed. menuInfo will contain an
@@ -196,34 +199,34 @@ public class ExpandableListActivity extends AppCompatActivity implements
@Override
public void onContentChanged() {
super.onContentChanged();
View emptyView = findViewById(R.id.empty);
mList = findViewById(R.id.list);
if (mList == null) {
final View emptyView = findViewById(R.id.empty);
list = findViewById(R.id.list);
if (list == null) {
throw new RuntimeException(
"Your content must have a ExpandableListView whose id attribute is " +
"'R.id.list'");
}
if (emptyView != null) {
mList.setEmptyView(emptyView);
list.setEmptyView(emptyView);
}
mList.setOnChildClickListener(this);
mList.setOnGroupExpandListener(this);
mList.setOnGroupCollapseListener(this);
list.setOnChildClickListener(this);
list.setOnGroupExpandListener(this);
list.setOnGroupCollapseListener(this);
if (mFinishedStart) {
setListAdapter(mAdapter);
if (finishedStart) {
setListAdapter(adapter);
}
mFinishedStart = true;
finishedStart = true;
}
/**
* Provide the adapter for the expandable list.
*/
public void setListAdapter(ExpandableListAdapter adapter) {
public void setListAdapter(final ExpandableListAdapter adapter) {
synchronized (this) {
ensureList();
mAdapter = adapter;
mList.setAdapter(adapter);
this.adapter = adapter;
list.setAdapter(adapter);
}
}
@@ -234,18 +237,18 @@ public class ExpandableListActivity extends AppCompatActivity implements
*/
public ExpandableListView getExpandableListView() {
ensureList();
return mList;
return list;
}
/**
* Get the ExpandableListAdapter associated with this activity's ExpandableListView.
*/
public ExpandableListAdapter getExpandableListAdapter() {
return mAdapter;
return adapter;
}
private void ensureList() {
if (mList != null) {
if (list != null) {
return;
}
setContentView(R.layout.expandable_list_content);
@@ -257,7 +260,7 @@ public class ExpandableListActivity extends AppCompatActivity implements
* @return The ID of the currently selected group or child.
*/
public long getSelectedId() {
return mList.getSelectedId();
return list.getSelectedId();
}
/**
@@ -267,7 +270,7 @@ public class ExpandableListActivity extends AppCompatActivity implements
* @return A packed position representation containing the currently selected group or child's position and type.
*/
public long getSelectedPosition() {
return mList.getSelectedPosition();
return list.getSelectedPosition();
}
/**
@@ -282,8 +285,8 @@ public class ExpandableListActivity extends AppCompatActivity implements
* Whether the child's group should be expanded if it is collapsed.
* @return Whether the selection was successfully set on the child.
*/
public boolean setSelectedChild(int groupPosition, int childPosition, boolean shouldExpandGroup) {
return mList.setSelectedChild(groupPosition, childPosition, shouldExpandGroup);
public boolean setSelectedChild(final int groupPosition, final int childPosition, final boolean shouldExpandGroup) {
return list.setSelectedChild(groupPosition, childPosition, shouldExpandGroup);
}
/**
@@ -292,8 +295,8 @@ public class ExpandableListActivity extends AppCompatActivity implements
* @param groupPosition
* The position of the group that should be selected.
*/
public void setSelectedGroup(int groupPosition) {
mList.setSelectedGroup(groupPosition);
public void setSelectedGroup(final int groupPosition) {
list.setSelectedGroup(groupPosition);
}
}

View File

@@ -5,6 +5,8 @@ import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.content.Context;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import android.util.Log;
@@ -23,16 +25,15 @@ import no.nordicsemi.android.nrftoolbox.profile.LoggableBleManager;
* @param <T> The profile callbacks type.
* @see BleManager
*/
@SuppressWarnings("WeakerAccess")
public abstract class BatteryManager<T extends BatteryManagerCallbacks> extends LoggableBleManager<T> {
/** Battery Service UUID. */
private final static UUID BATTERY_SERVICE_UUID = UUID.fromString("0000180F-0000-1000-8000-00805f9b34fb");
/** Battery Level characteristic UUID. */
private final static UUID BATTERY_LEVEL_CHARACTERISTIC_UUID = UUID.fromString("00002A19-0000-1000-8000-00805f9b34fb");
private BluetoothGattCharacteristic mBatteryLevelCharacteristic;
private BluetoothGattCharacteristic batteryLevelCharacteristic;
/** Last received Battery Level value. */
private Integer mBatteryLevel;
private Integer batteryLevel;
/**
* The manager constructor.
@@ -43,12 +44,13 @@ public abstract class BatteryManager<T extends BatteryManagerCallbacks> extends
super(context);
}
private DataReceivedCallback mBatteryLevelDataCallback = new BatteryLevelDataCallback() {
private DataReceivedCallback batteryLevelDataCallback = new BatteryLevelDataCallback() {
@Override
public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) {
public void onBatteryLevelChanged(@NonNull final BluetoothDevice device,
@IntRange(from = 0, to = 100) final int batteryLevel) {
log(LogContract.Log.Level.APPLICATION,"Battery Level received: " + batteryLevel + "%");
mBatteryLevel = batteryLevel;
mCallbacks.onBatteryLevelChanged(device, batteryLevel);
BatteryManager.this.batteryLevel = batteryLevel;
callbacks.onBatteryLevelChanged(device, batteryLevel);
}
@Override
@@ -59,8 +61,8 @@ public abstract class BatteryManager<T extends BatteryManagerCallbacks> extends
public void readBatteryLevelCharacteristic() {
if (isConnected()) {
readCharacteristic(mBatteryLevelCharacteristic)
.with(mBatteryLevelDataCallback)
readCharacteristic(batteryLevelCharacteristic)
.with(batteryLevelDataCallback)
.fail((device, status) -> log(Log.WARN,"Battery Level characteristic not found"))
.enqueue();
}
@@ -69,9 +71,9 @@ public abstract class BatteryManager<T extends BatteryManagerCallbacks> extends
public void enableBatteryLevelCharacteristicNotifications() {
if (isConnected()) {
// If the Battery Level characteristic is null, the request will be ignored
setNotificationCallback(mBatteryLevelCharacteristic)
.with(mBatteryLevelDataCallback);
enableNotifications(mBatteryLevelCharacteristic)
setNotificationCallback(batteryLevelCharacteristic)
.with(batteryLevelDataCallback);
enableNotifications(batteryLevelCharacteristic)
.done(device -> log(Log.INFO, "Battery Level notifications enabled"))
.fail((device, status) -> log(Log.WARN, "Battery Level characteristic not found"))
.enqueue();
@@ -83,7 +85,7 @@ public abstract class BatteryManager<T extends BatteryManagerCallbacks> extends
*/
public void disableBatteryLevelCharacteristicNotifications() {
if (isConnected()) {
disableNotifications(mBatteryLevelCharacteristic)
disableNotifications(batteryLevelCharacteristic)
.done(device -> log(Log.INFO, "Battery Level notifications disabled"))
.enqueue();
}
@@ -95,7 +97,7 @@ public abstract class BatteryManager<T extends BatteryManagerCallbacks> extends
* @return Battery Level value, in percent.
*/
public Integer getBatteryLevel() {
return mBatteryLevel;
return batteryLevel;
}
protected abstract class BatteryManagerGattCallback extends BleManagerGattCallback {
@@ -110,15 +112,15 @@ public abstract class BatteryManager<T extends BatteryManagerCallbacks> extends
protected boolean isOptionalServiceSupported(@NonNull final BluetoothGatt gatt) {
final BluetoothGattService service = gatt.getService(BATTERY_SERVICE_UUID);
if (service != null) {
mBatteryLevelCharacteristic = service.getCharacteristic(BATTERY_LEVEL_CHARACTERISTIC_UUID);
batteryLevelCharacteristic = service.getCharacteristic(BATTERY_LEVEL_CHARACTERISTIC_UUID);
}
return mBatteryLevelCharacteristic != null;
return batteryLevelCharacteristic != null;
}
@Override
protected void onDeviceDisconnected() {
mBatteryLevelCharacteristic = null;
mBatteryLevel = null;
batteryLevelCharacteristic = null;
batteryLevel = null;
}
}
}

View File

@@ -41,15 +41,15 @@ public class BPMActivity extends BleProfileActivity implements BPMManagerCallbac
@SuppressWarnings("unused")
private static final String TAG = "BPMActivity";
private TextView mSystolicView;
private TextView mSystolicUnitView;
private TextView mDiastolicView;
private TextView mDiastolicUnitView;
private TextView mMeanAPView;
private TextView mMeanAPUnitView;
private TextView mPulseView;
private TextView mTimestampView;
private TextView mBatteryLevelView;
private TextView systolicView;
private TextView systolicUnitView;
private TextView diastolicView;
private TextView diastolicUnitView;
private TextView meanAPView;
private TextView meanAPUnitView;
private TextView pulseView;
private TextView timestampView;
private TextView batteryLevelView;
@Override
protected void onCreateView(final Bundle savedInstanceState) {
@@ -58,15 +58,15 @@ public class BPMActivity extends BleProfileActivity implements BPMManagerCallbac
}
private void setGUI() {
mSystolicView = findViewById(R.id.systolic);
mSystolicUnitView = findViewById(R.id.systolic_unit);
mDiastolicView = findViewById(R.id.diastolic);
mDiastolicUnitView = findViewById(R.id.diastolic_unit);
mMeanAPView = findViewById(R.id.mean_ap);
mMeanAPUnitView = findViewById(R.id.mean_ap_unit);
mPulseView = findViewById(R.id.pulse);
mTimestampView = findViewById(R.id.timestamp);
mBatteryLevelView = findViewById(R.id.battery);
systolicView = findViewById(R.id.systolic);
systolicUnitView = findViewById(R.id.systolic_unit);
diastolicView = findViewById(R.id.diastolic);
diastolicUnitView = findViewById(R.id.diastolic_unit);
meanAPView = findViewById(R.id.mean_ap);
meanAPUnitView = findViewById(R.id.mean_ap_unit);
pulseView = findViewById(R.id.pulse);
timestampView = findViewById(R.id.timestamp);
batteryLevelView = findViewById(R.id.battery);
}
@Override
@@ -92,21 +92,21 @@ public class BPMActivity extends BleProfileActivity implements BPMManagerCallbac
@Override
protected LoggableBleManager<BPMManagerCallbacks> initializeManager() {
final BPMManager manager = BPMManager.getBPMManager(getApplicationContext());
manager.setGattCallbacks(this);
manager.setManagerCallbacks(this);
return manager;
}
@Override
protected void setDefaultUI() {
mSystolicView.setText(R.string.not_available_value);
mSystolicUnitView.setText(null);
mDiastolicView.setText(R.string.not_available_value);
mDiastolicUnitView.setText(null);
mMeanAPView.setText(R.string.not_available_value);
mMeanAPUnitView.setText(null);
mPulseView.setText(R.string.not_available_value);
mTimestampView.setText(R.string.not_available);
mBatteryLevelView.setText(R.string.not_available);
systolicView.setText(R.string.not_available_value);
systolicUnitView.setText(null);
diastolicView.setText(R.string.not_available_value);
diastolicUnitView.setText(null);
meanAPView.setText(R.string.not_available_value);
meanAPUnitView.setText(null);
pulseView.setText(R.string.not_available_value);
timestampView.setText(R.string.not_available);
batteryLevelView.setText(R.string.not_available);
}
@Override
@@ -122,7 +122,7 @@ public class BPMActivity extends BleProfileActivity implements BPMManagerCallbac
@Override
public void onDeviceDisconnected(@NonNull final BluetoothDevice device) {
super.onDeviceDisconnected(device);
runOnUiThread(() -> mBatteryLevelView.setText(R.string.not_available));
runOnUiThread(() -> batteryLevelView.setText(R.string.not_available));
}
@Override
@@ -131,21 +131,21 @@ public class BPMActivity extends BleProfileActivity implements BPMManagerCallbac
@Nullable final Float pulseRate, @Nullable final Integer userID,
@Nullable final BPMStatus status, @Nullable final Calendar calendar) {
runOnUiThread(() -> {
mSystolicView.setText(String.valueOf(systolic));
mDiastolicView.setText(String.valueOf(diastolic));
mMeanAPView.setText(String.valueOf(meanArterialPressure));
systolicView.setText(String.valueOf(systolic));
diastolicView.setText(String.valueOf(diastolic));
meanAPView.setText(String.valueOf(meanArterialPressure));
if (pulseRate != null)
mPulseView.setText(String.valueOf(pulseRate));
pulseView.setText(String.valueOf(pulseRate));
else
mPulseView.setText(R.string.not_available_value);
pulseView.setText(R.string.not_available_value);
if (calendar != null)
mTimestampView.setText(getString(R.string.bpm_timestamp, calendar));
timestampView.setText(getString(R.string.bpm_timestamp, calendar));
else
mTimestampView.setText(R.string.not_available);
timestampView.setText(R.string.not_available);
mSystolicUnitView.setText(unit == BloodPressureMeasurementCallback.UNIT_mmHg ? R.string.bpm_unit_mmhg : R.string.bpm_unit_kpa);
mDiastolicUnitView.setText(unit == BloodPressureMeasurementCallback.UNIT_mmHg ? R.string.bpm_unit_mmhg : R.string.bpm_unit_kpa);
mMeanAPUnitView.setText(unit == BloodPressureMeasurementCallback.UNIT_mmHg ? R.string.bpm_unit_mmhg : R.string.bpm_unit_kpa);
systolicUnitView.setText(unit == BloodPressureMeasurementCallback.UNIT_mmHg ? R.string.bpm_unit_mmhg : R.string.bpm_unit_kpa);
diastolicUnitView.setText(unit == BloodPressureMeasurementCallback.UNIT_mmHg ? R.string.bpm_unit_mmhg : R.string.bpm_unit_kpa);
meanAPUnitView.setText(unit == BloodPressureMeasurementCallback.UNIT_mmHg ? R.string.bpm_unit_mmhg : R.string.bpm_unit_kpa);
});
}
@@ -154,26 +154,26 @@ public class BPMActivity extends BleProfileActivity implements BPMManagerCallbac
@Nullable final Float pulseRate, @Nullable final Integer userID,
@Nullable final BPMStatus status, @Nullable final Calendar calendar) {
runOnUiThread(() -> {
mSystolicView.setText(String.valueOf(cuffPressure));
mDiastolicView.setText(R.string.not_available_value);
mMeanAPView.setText(R.string.not_available_value);
systolicView.setText(String.valueOf(cuffPressure));
diastolicView.setText(R.string.not_available_value);
meanAPView.setText(R.string.not_available_value);
if (pulseRate != null)
mPulseView.setText(String.valueOf(pulseRate));
pulseView.setText(String.valueOf(pulseRate));
else
mPulseView.setText(R.string.not_available_value);
pulseView.setText(R.string.not_available_value);
if (calendar != null)
mTimestampView.setText(getString(R.string.bpm_timestamp, calendar));
timestampView.setText(getString(R.string.bpm_timestamp, calendar));
else
mTimestampView.setText(R.string.not_available);
timestampView.setText(R.string.not_available);
mSystolicUnitView.setText(unit == IntermediateCuffPressureCallback.UNIT_mmHg ? R.string.bpm_unit_mmhg : R.string.bpm_unit_kpa);
mDiastolicUnitView.setText(null);
mMeanAPUnitView.setText(null);
systolicUnitView.setText(unit == IntermediateCuffPressureCallback.UNIT_mmHg ? R.string.bpm_unit_mmhg : R.string.bpm_unit_kpa);
diastolicUnitView.setText(null);
meanAPUnitView.setText(null);
});
}
@Override
public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) {
runOnUiThread(() -> mBatteryLevelView.setText(getString(R.string.battery, batteryLevel)));
runOnUiThread(() -> batteryLevelView.setText(getString(R.string.battery, batteryLevel)));
}
}

View File

@@ -50,7 +50,7 @@ public class BPMManager extends BatteryManager<BPMManagerCallbacks> {
/** Intermediate Cuff Pressure characteristic UUID. */
private static final UUID ICP_CHARACTERISTIC_UUID = UUID.fromString("00002A36-0000-1000-8000-00805f9b34fb");
private BluetoothGattCharacteristic mBPMCharacteristic, mICPCharacteristic;
private BluetoothGattCharacteristic bpmCharacteristic, icpCharacteristic;
private static BPMManager managerInstance = null;
@@ -71,20 +71,20 @@ public class BPMManager extends BatteryManager<BPMManagerCallbacks> {
@NonNull
@Override
protected BatteryManagerGattCallback getGattCallback() {
return mGattCallback;
return gattCallback;
}
/**
* BluetoothGatt callbacks for connection/disconnection, service discovery,
* receiving notification, etc.
*/
private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() {
private final BatteryManagerGattCallback gattCallback = new BatteryManagerGattCallback() {
@Override
protected void initialize() {
super.initialize();
setNotificationCallback(mICPCharacteristic)
setNotificationCallback(icpCharacteristic)
.with(new IntermediateCuffPressureDataCallback() {
@Override
public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
@@ -99,7 +99,7 @@ public class BPMManager extends BatteryManager<BPMManagerCallbacks> {
final float cuffPressure, final int unit,
@Nullable final Float pulseRate, @Nullable final Integer userID,
@Nullable final BPMStatus status, @Nullable final Calendar calendar) {
mCallbacks.onIntermediateCuffPressureReceived(device, cuffPressure, unit, pulseRate, userID, status, calendar);
callbacks.onIntermediateCuffPressureReceived(device, cuffPressure, unit, pulseRate, userID, status, calendar);
}
@Override
@@ -107,7 +107,7 @@ public class BPMManager extends BatteryManager<BPMManagerCallbacks> {
log(Log.WARN, "Invalid ICP data received: " + data);
}
});
setIndicationCallback(mBPMCharacteristic)
setIndicationCallback(bpmCharacteristic)
.with(new BloodPressureMeasurementDataCallback() {
@Override
public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
@@ -123,7 +123,7 @@ public class BPMManager extends BatteryManager<BPMManagerCallbacks> {
final int unit, @Nullable final Float pulseRate,
@Nullable final Integer userID, @Nullable final BPMStatus status,
@Nullable final Calendar calendar) {
mCallbacks.onBloodPressureMeasurementReceived(device, systolic, diastolic,
callbacks.onBloodPressureMeasurementReceived(device, systolic, diastolic,
meanArterialPressure, unit, pulseRate, userID, status, calendar);
}
@@ -133,33 +133,33 @@ public class BPMManager extends BatteryManager<BPMManagerCallbacks> {
}
});
enableNotifications(mICPCharacteristic)
enableNotifications(icpCharacteristic)
.fail((device, status) -> log(Log.WARN,
"Intermediate Cuff Pressure characteristic not found"))
.enqueue();
enableIndications(mBPMCharacteristic).enqueue();
enableIndications(bpmCharacteristic).enqueue();
}
@Override
protected boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) {
final BluetoothGattService service = gatt.getService(BP_SERVICE_UUID);
if (service != null) {
mBPMCharacteristic = service.getCharacteristic(BPM_CHARACTERISTIC_UUID);
mICPCharacteristic = service.getCharacteristic(ICP_CHARACTERISTIC_UUID);
bpmCharacteristic = service.getCharacteristic(BPM_CHARACTERISTIC_UUID);
icpCharacteristic = service.getCharacteristic(ICP_CHARACTERISTIC_UUID);
}
return mBPMCharacteristic != null;
return bpmCharacteristic != null;
}
@Override
protected boolean isOptionalServiceSupported(@NonNull final BluetoothGatt gatt) {
super.isOptionalServiceSupported(gatt); // ignore the result of this
return mICPCharacteristic != null;
return icpCharacteristic != null;
}
@Override
protected void onDeviceDisconnected() {
mICPCharacteristic = null;
mBPMCharacteristic = null;
icpCharacteristic = null;
bpmCharacteristic = null;
}
};
}

View File

@@ -28,6 +28,8 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import android.util.SparseArray;
import android.view.MenuInflater;
@@ -45,13 +47,13 @@ import no.nordicsemi.android.nrftoolbox.profile.BleProfileServiceReadyActivity;
import no.nordicsemi.android.nrftoolbox.proximity.ProximityService;
public class CGMSActivity extends BleProfileServiceReadyActivity<CGMService.CGMSBinder> implements PopupMenu.OnMenuItemClickListener {
private View mControlPanelStd;
private View mControlPanelAbort;
private ListView mRecordsListView;
private TextView mBatteryLevelView;
private CGMSRecordsAdapter mCgmsRecordsAdapter;
private View controlPanelStd;
private View controlPanelAbort;
private ListView recordsListView;
private TextView batteryLevelView;
private CGMSRecordsAdapter cgmsRecordsAdapter;
private CGMService.CGMSBinder mBinder;
private CGMService.CGMSBinder binder;
@Override
protected void onCreateView(Bundle savedInstanceState) {
@@ -61,32 +63,32 @@ public class CGMSActivity extends BleProfileServiceReadyActivity<CGMService.CGMS
@Override
protected void onInitialize(Bundle savedInstanceState) {
LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, makeIntentFilter());
LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, makeIntentFilter());
}
private void setGUI() {
mRecordsListView = findViewById(R.id.list);
mControlPanelStd = findViewById(R.id.cgms_control_std);
mControlPanelAbort = findViewById(R.id.cgms_control_abort);
mBatteryLevelView = findViewById(R.id.battery);
recordsListView = findViewById(R.id.list);
controlPanelStd = findViewById(R.id.cgms_control_std);
controlPanelAbort = findViewById(R.id.cgms_control_abort);
batteryLevelView = findViewById(R.id.battery);
findViewById(R.id.action_last).setOnClickListener(v -> {
clearRecords();
if (mBinder != null) {
mBinder.clear();
mBinder.getLastRecord();
if (binder != null) {
binder.clear();
binder.getLastRecord();
}
});
findViewById(R.id.action_all).setOnClickListener(v -> {
clearRecords();
if (mBinder != null) {
if (binder != null) {
clearRecords();
mBinder.getAllRecords();
binder.getAllRecords();
}
});
findViewById(R.id.action_abort).setOnClickListener(v -> {
if (mBinder != null) {
mBinder.abort();
if (binder != null) {
binder.abort();
}
});
@@ -101,27 +103,27 @@ public class CGMSActivity extends BleProfileServiceReadyActivity<CGMService.CGMS
}
private void loadAdapter(SparseArray<CGMSRecord> records) {
mCgmsRecordsAdapter.clear();
cgmsRecordsAdapter.clear();
for (int i = 0; i < records.size(); i++) {
mCgmsRecordsAdapter.addItem(records.valueAt(i));
cgmsRecordsAdapter.addItem(records.valueAt(i));
}
mCgmsRecordsAdapter.notifyDataSetChanged();
cgmsRecordsAdapter.notifyDataSetChanged();
}
@Override
protected void onDestroy() {
super.onDestroy();
LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver);
LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver);
}
@Override
protected void onServiceBound(final CGMService.CGMSBinder binder) {
mBinder = binder;
this.binder = binder;
final SparseArray<CGMSRecord> cgmsRecords = binder.getRecords();
if (cgmsRecords != null && cgmsRecords.size() > 0) {
if (mCgmsRecordsAdapter == null) {
mCgmsRecordsAdapter = new CGMSRecordsAdapter(CGMSActivity.this);
mRecordsListView.setAdapter(mCgmsRecordsAdapter);
if (cgmsRecordsAdapter == null) {
cgmsRecordsAdapter = new CGMSRecordsAdapter(CGMSActivity.this);
recordsListView.setAdapter(cgmsRecordsAdapter);
}
loadAdapter(cgmsRecords);
}
@@ -129,7 +131,7 @@ public class CGMSActivity extends BleProfileServiceReadyActivity<CGMService.CGMS
@Override
protected void onServiceUnbound() {
mBinder = null;
binder = null;
}
@Override
@@ -158,31 +160,31 @@ public class CGMSActivity extends BleProfileServiceReadyActivity<CGMService.CGMS
}
@Override
public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) {
public void onServicesDiscovered(@NonNull final BluetoothDevice device, final boolean optionalServicesFound) {
// this may notify user or show some views
}
private void setOperationInProgress(final boolean progress) {
runOnUiThread(() -> {
// setSupportProgressBarIndeterminateVisibility(progress);
mControlPanelStd.setVisibility(!progress ? View.VISIBLE : View.GONE);
mControlPanelAbort.setVisibility(progress ? View.VISIBLE : View.GONE);
controlPanelStd.setVisibility(!progress ? View.VISIBLE : View.GONE);
controlPanelAbort.setVisibility(progress ? View.VISIBLE : View.GONE);
});
}
public void onBatteryLevelChanged(final BluetoothDevice device, final int value) {
mBatteryLevelView.setText(getString(R.string.battery, value));
public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int value) {
batteryLevelView.setText(getString(R.string.battery, value));
}
@Override
public void onDeviceDisconnected(final BluetoothDevice device) {
public void onDeviceDisconnected(@NonNull final BluetoothDevice device) {
super.onDeviceDisconnected(device);
setOperationInProgress(false);
mBatteryLevelView.setText(R.string.not_available);
batteryLevelView.setText(R.string.not_available);
}
@Override
public void onError(final BluetoothDevice device, final String message, final int errorCode) {
public void onError(@NonNull final BluetoothDevice device, @NonNull final String message, final int errorCode) {
super.onError(device, message, errorCode);
setOperationInProgress(false);
}
@@ -190,40 +192,40 @@ public class CGMSActivity extends BleProfileServiceReadyActivity<CGMService.CGMS
@Override
protected void setDefaultUI() {
clearRecords();
mBatteryLevelView.setText(R.string.not_available);
batteryLevelView.setText(R.string.not_available);
}
@Override
public boolean onMenuItemClick(MenuItem menuItem) {
switch (menuItem.getItemId()) {
case R.id.action_refresh:
if(mBinder != null)
mBinder.refreshRecords();
if(binder != null)
binder.refreshRecords();
break;
case R.id.action_first:
if (mBinder != null)
mBinder.getFirstRecord();
if (binder != null)
binder.getFirstRecord();
break;
case R.id.action_clear:
if (mBinder != null)
mBinder.clear();
if (binder != null)
binder.clear();
break;
case R.id.action_delete_all:
if (mBinder != null)
mBinder.deleteAllRecords();
if (binder != null)
binder.deleteAllRecords();
break;
}
return true;
}
private void clearRecords() {
if (mCgmsRecordsAdapter != null) {
mCgmsRecordsAdapter.clear();
mCgmsRecordsAdapter.notifyDataSetChanged();
if (cgmsRecordsAdapter != null) {
cgmsRecordsAdapter.clear();
cgmsRecordsAdapter.notifyDataSetChanged();
}
}
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
final String action = intent.getAction();
@@ -232,12 +234,12 @@ public class CGMSActivity extends BleProfileServiceReadyActivity<CGMService.CGMS
switch (action) {
case CGMService.BROADCAST_NEW_CGMS_VALUE: {
CGMSRecord cgmsRecord = intent.getExtras().getParcelable(CGMService.EXTRA_CGMS_RECORD);
if (mCgmsRecordsAdapter == null) {
mCgmsRecordsAdapter = new CGMSRecordsAdapter(CGMSActivity.this);
mRecordsListView.setAdapter(mCgmsRecordsAdapter);
if (cgmsRecordsAdapter == null) {
cgmsRecordsAdapter = new CGMSRecordsAdapter(CGMSActivity.this);
recordsListView.setAdapter(cgmsRecordsAdapter);
}
mCgmsRecordsAdapter.addItem(cgmsRecord);
mCgmsRecordsAdapter.notifyDataSetChanged();
cgmsRecordsAdapter.addItem(cgmsRecord);
cgmsRecordsAdapter.notifyDataSetChanged();
break;
}
case CGMService.BROADCAST_DATA_SET_CLEAR:

View File

@@ -22,18 +22,19 @@
package no.nordicsemi.android.nrftoolbox.cgms;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.util.Log;
import android.util.SparseArray;
import java.util.UUID;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import no.nordicsemi.android.ble.common.callback.RecordAccessControlPointDataCallback;
import no.nordicsemi.android.ble.common.callback.cgm.CGMFeatureDataCallback;
import no.nordicsemi.android.ble.common.callback.cgm.CGMSpecificOpsControlPointDataCallback;
@@ -48,9 +49,9 @@ import no.nordicsemi.android.nrftoolbox.parser.CGMMeasurementParser;
import no.nordicsemi.android.nrftoolbox.parser.CGMSpecificOpsControlPointParser;
import no.nordicsemi.android.nrftoolbox.parser.RecordAccessControlPointParser;
public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
/** Cycling Speed and Cadence service UUID. */
public static final UUID CGMS_UUID = UUID.fromString("0000181F-0000-1000-8000-00805f9b34fb");
static final UUID CGMS_UUID = UUID.fromString("0000181F-0000-1000-8000-00805f9b34fb");
private static final UUID CGM_STATUS_UUID = UUID.fromString("00002AA9-0000-1000-8000-00805f9b34fb");
private static final UUID CGM_FEATURE_UUID = UUID.fromString("00002AA8-0000-1000-8000-00805f9b34fb");
private static final UUID CGM_MEASUREMENT_UUID = UUID.fromString("00002AA7-0000-1000-8000-00805f9b34fb");
@@ -58,26 +59,26 @@ public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
/** Record Access Control Point characteristic UUID. */
private static final UUID RACP_UUID = UUID.fromString("00002A52-0000-1000-8000-00805f9b34fb");
private BluetoothGattCharacteristic mCGMStatusCharacteristic;
private BluetoothGattCharacteristic mCGMFeatureCharacteristic;
private BluetoothGattCharacteristic mCGMMeasurementCharacteristic;
private BluetoothGattCharacteristic mCGMSpecificOpsControlPointCharacteristic;
private BluetoothGattCharacteristic mRecordAccessControlPointCharacteristic;
private BluetoothGattCharacteristic cgmStatusCharacteristic;
private BluetoothGattCharacteristic cgmFeatureCharacteristic;
private BluetoothGattCharacteristic cgmMeasurementCharacteristic;
private BluetoothGattCharacteristic cgmSpecificOpsControlPointCharacteristic;
private BluetoothGattCharacteristic recordAccessControlPointCharacteristic;
private SparseArray<CGMSRecord> mRecords = new SparseArray<>();
private SparseArray<CGMSRecord> records = new SparseArray<>();
/** A flag set to true if the remote device supports E2E CRC. */
private boolean mSecured;
private boolean secured;
/**
* A flag set when records has been requested using RACP. This is to distinguish CGM packets
* received as continuous measurements or requested.
*/
private boolean mRecordAccessRequestInProgress;
private boolean recordAccessRequestInProgress;
/**
* The timestamp when the session has started. This is needed to display the user facing
* times of samples.
*/
private long mSessionStartTime;
private long sessionStartTime;
CGMSManager(final Context context) {
super(context);
@@ -86,14 +87,14 @@ public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
@NonNull
@Override
protected BatteryManagerGattCallback getGattCallback() {
return mGattCallback;
return gattCallback;
}
/**
* BluetoothGatt callbacks for connection/disconnection, service discovery,
* receiving notification, etc.
*/
private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() {
private final BatteryManagerGattCallback gattCallback = new BatteryManagerGattCallback() {
@Override
protected void initialize() {
@@ -102,25 +103,25 @@ public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
// Read CGM Feature characteristic, mainly to see if the device supports E2E CRC.
// This is not supported in the experimental CGMS from the SDK.
readCharacteristic(mCGMFeatureCharacteristic)
readCharacteristic(cgmFeatureCharacteristic)
.with(new CGMFeatureDataCallback() {
@Override
public void onContinuousGlucoseMonitorFeaturesReceived(@NonNull final BluetoothDevice device, @NonNull final CGMFeatures features,
final int type, final int sampleLocation, final boolean secured) {
mSecured = features.e2eCrcSupported;
log(LogContract.Log.Level.APPLICATION, "E2E CRC feature " + (mSecured ? "supported" : "not supported"));
CGMSManager.this.secured = features.e2eCrcSupported;
log(LogContract.Log.Level.APPLICATION, "E2E CRC feature " + (CGMSManager.this.secured ? "supported" : "not supported"));
}
})
.fail((device, status) -> log(Log.WARN, "Could not read CGM Feature characteristic"))
.enqueue();
// Check if the session is already started. This is not supported in the experimental CGMS from the SDK.
readCharacteristic(mCGMStatusCharacteristic)
readCharacteristic(cgmStatusCharacteristic)
.with(new CGMStatusDataCallback() {
@Override
public void onContinuousGlucoseMonitorStatusChanged(@NonNull final BluetoothDevice device, @NonNull final CGMStatus status, final int timeOffset, final boolean secured) {
if (!status.sessionStopped) {
mSessionStartTime = System.currentTimeMillis() - timeOffset * 60000L;
sessionStartTime = System.currentTimeMillis() - timeOffset * 60000L;
log(LogContract.Log.Level.APPLICATION, "Session already started");
}
}
@@ -129,7 +130,7 @@ public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
.enqueue();
// Set notification and indication callbacks
setNotificationCallback(mCGMMeasurementCharacteristic)
setNotificationCallback(cgmMeasurementCharacteristic)
.with(new ContinuousGlucoseMeasurementDataCallback() {
@Override
public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
@@ -147,16 +148,16 @@ public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
final boolean secured) {
// If the CGM Status characteristic has not been read and the session was already started before,
// estimate the Session Start Time by subtracting timeOffset minutes from the current timestamp.
if (mSessionStartTime == 0 && !mRecordAccessRequestInProgress) {
mSessionStartTime = System.currentTimeMillis() - timeOffset * 60000L;
if (sessionStartTime == 0 && !recordAccessRequestInProgress) {
sessionStartTime = System.currentTimeMillis() - timeOffset * 60000L;
}
// Calculate the sample timestamp based on the Session Start Time
final long timestamp = mSessionStartTime + (timeOffset * 60000L); // Sequence number is in minutes since Start Session
final long timestamp = sessionStartTime + (timeOffset * 60000L); // Sequence number is in minutes since Start Session
final CGMSRecord record = new CGMSRecord(timeOffset, glucoseConcentration, timestamp);
mRecords.put(record.sequenceNumber, record);
mCallbacks.onCGMValueReceived(device, record);
records.put(record.sequenceNumber, record);
callbacks.onCGMValueReceived(device, record);
}
@Override
@@ -166,7 +167,7 @@ public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
}
});
setIndicationCallback(mCGMSpecificOpsControlPointCharacteristic)
setIndicationCallback(cgmSpecificOpsControlPointCharacteristic)
.with(new CGMSpecificOpsControlPointDataCallback() {
@Override
public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
@@ -174,23 +175,27 @@ public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
super.onDataReceived(device, data);
}
@SuppressLint("SwitchIntDef")
@Override
public void onCGMSpecificOpsOperationCompleted(@NonNull final BluetoothDevice device,
final int requestCode, final boolean secured) {
@CGMOpCode final int requestCode,
final boolean secured) {
switch (requestCode) {
case CGM_OP_CODE_START_SESSION:
mSessionStartTime = System.currentTimeMillis();
sessionStartTime = System.currentTimeMillis();
break;
case CGM_OP_CODE_STOP_SESSION:
mSessionStartTime = 0;
sessionStartTime = 0;
break;
}
}
@SuppressLint("SwitchIntDef")
@SuppressWarnings("StatementWithEmptyBody")
@Override
public void onCGMSpecificOpsOperationError(@NonNull final BluetoothDevice device,
final int requestCode, final int errorCode,
@CGMOpCode final int requestCode,
@CGMErrorCode final int errorCode,
final boolean secured) {
switch (requestCode) {
case CGM_OP_CODE_START_SESSION:
@@ -202,7 +207,7 @@ public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
// packet is received based on it's Time Offset.
}
case CGM_OP_CODE_STOP_SESSION:
mSessionStartTime = 0;
sessionStartTime = 0;
break;
}
}
@@ -214,7 +219,7 @@ public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
}
});
setIndicationCallback(mRecordAccessControlPointCharacteristic)
setIndicationCallback(recordAccessControlPointCharacteristic)
.with(new RecordAccessControlPointDataCallback() {
@Override
public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
@@ -222,72 +227,76 @@ public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
super.onDataReceived(device, data);
}
@SuppressLint("SwitchIntDef")
@Override
public void onRecordAccessOperationCompleted(@NonNull final BluetoothDevice device, final int requestCode) {
public void onRecordAccessOperationCompleted(@NonNull final BluetoothDevice device,
@RACPOpCode final int requestCode) {
//noinspection SwitchStatementWithTooFewBranches
switch (requestCode) {
case RACP_OP_CODE_ABORT_OPERATION:
mCallbacks.onOperationAborted(device);
callbacks.onOperationAborted(device);
break;
default:
mRecordAccessRequestInProgress = false;
mCallbacks.onOperationCompleted(device);
recordAccessRequestInProgress = false;
callbacks.onOperationCompleted(device);
break;
}
}
@Override
public void onRecordAccessOperationCompletedWithNoRecordsFound(@NonNull final BluetoothDevice device,
final int requestCode) {
mRecordAccessRequestInProgress = false;
mCallbacks.onOperationCompleted(device);
@RACPOpCode final int requestCode) {
recordAccessRequestInProgress = false;
callbacks.onOperationCompleted(device);
}
@Override
public void onNumberOfRecordsReceived(@NonNull final BluetoothDevice device, final int numberOfRecords) {
mCallbacks.onNumberOfRecordsRequested(device, numberOfRecords);
callbacks.onNumberOfRecordsRequested(device, numberOfRecords);
if (numberOfRecords > 0) {
if (mRecords.size() > 0) {
final int sequenceNumber = mRecords.keyAt(mRecords.size() - 1) + 1;
writeCharacteristic(mRecordAccessControlPointCharacteristic,
if (records.size() > 0) {
final int sequenceNumber = records.keyAt(records.size() - 1) + 1;
writeCharacteristic(recordAccessControlPointCharacteristic,
RecordAccessControlPointData.reportStoredRecordsGreaterThenOrEqualTo(sequenceNumber))
.enqueue();
} else {
writeCharacteristic(mRecordAccessControlPointCharacteristic,
writeCharacteristic(recordAccessControlPointCharacteristic,
RecordAccessControlPointData.reportAllStoredRecords())
.enqueue();
}
} else {
mRecordAccessRequestInProgress = false;
mCallbacks.onOperationCompleted(device);
recordAccessRequestInProgress = false;
callbacks.onOperationCompleted(device);
}
}
@Override
public void onRecordAccessOperationError(@NonNull final BluetoothDevice device,
final int requestCode, final int errorCode) {
@RACPOpCode final int requestCode,
@RACPErrorCode final int errorCode) {
log(Log.WARN, "Record Access operation failed (error " + errorCode + ")");
if (errorCode == RACP_ERROR_OP_CODE_NOT_SUPPORTED) {
mCallbacks.onOperationNotSupported(device);
callbacks.onOperationNotSupported(device);
} else {
mCallbacks.onOperationFailed(device);
callbacks.onOperationFailed(device);
}
}
});
// Enable notifications and indications
enableNotifications(mCGMMeasurementCharacteristic)
enableNotifications(cgmMeasurementCharacteristic)
.fail((device, status) -> log(Log.WARN, "Failed to enable Continuous Glucose Measurement notifications (" + status + ")"))
.enqueue();
enableIndications(mCGMSpecificOpsControlPointCharacteristic)
enableIndications(cgmSpecificOpsControlPointCharacteristic)
.fail((device, status) -> log(Log.WARN, "Failed to enable CGM Specific Ops Control Point indications notifications (" + status + ")"))
.enqueue();
enableIndications(mRecordAccessControlPointCharacteristic)
enableIndications(recordAccessControlPointCharacteristic)
.fail((device, status) -> log(Log.WARN, "Failed to enabled Record Access Control Point indications (error " + status + ")"))
.enqueue();
// Start Continuous Glucose session if hasn't been started before
if (mSessionStartTime == 0L) {
writeCharacteristic(mCGMSpecificOpsControlPointCharacteristic, CGMSpecificOpsControlPointData.startSession(mSecured))
if (sessionStartTime == 0L) {
writeCharacteristic(cgmSpecificOpsControlPointCharacteristic, CGMSpecificOpsControlPointData.startSession(secured))
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + CGMSpecificOpsControlPointParser.parse(data) + "\" sent"))
.fail((device, status) -> log(LogContract.Log.Level.ERROR, "Failed to start session (error " + status + ")"))
.enqueue();
@@ -298,41 +307,41 @@ public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
protected boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) {
final BluetoothGattService service = gatt.getService(CGMS_UUID);
if (service != null) {
mCGMStatusCharacteristic = service.getCharacteristic(CGM_STATUS_UUID);
mCGMFeatureCharacteristic = service.getCharacteristic(CGM_FEATURE_UUID);
mCGMMeasurementCharacteristic = service.getCharacteristic(CGM_MEASUREMENT_UUID);
mCGMSpecificOpsControlPointCharacteristic = service.getCharacteristic(CGM_OPS_CONTROL_POINT_UUID);
mRecordAccessControlPointCharacteristic = service.getCharacteristic(RACP_UUID);
cgmStatusCharacteristic = service.getCharacteristic(CGM_STATUS_UUID);
cgmFeatureCharacteristic = service.getCharacteristic(CGM_FEATURE_UUID);
cgmMeasurementCharacteristic = service.getCharacteristic(CGM_MEASUREMENT_UUID);
cgmSpecificOpsControlPointCharacteristic = service.getCharacteristic(CGM_OPS_CONTROL_POINT_UUID);
recordAccessControlPointCharacteristic = service.getCharacteristic(RACP_UUID);
}
return mCGMMeasurementCharacteristic != null
&& mCGMSpecificOpsControlPointCharacteristic != null
&& mRecordAccessControlPointCharacteristic != null;
return cgmMeasurementCharacteristic != null
&& cgmSpecificOpsControlPointCharacteristic != null
&& recordAccessControlPointCharacteristic != null;
}
@Override
protected void onDeviceDisconnected() {
super.onDeviceDisconnected();
mCGMStatusCharacteristic = null;
mCGMFeatureCharacteristic = null;
mCGMMeasurementCharacteristic = null;
mCGMSpecificOpsControlPointCharacteristic = null;
mRecordAccessControlPointCharacteristic = null;
cgmStatusCharacteristic = null;
cgmFeatureCharacteristic = null;
cgmMeasurementCharacteristic = null;
cgmSpecificOpsControlPointCharacteristic = null;
recordAccessControlPointCharacteristic = null;
}
};
/**
* Returns a list of CGM records obtained from this device. The key in the array is the
*/
public SparseArray<CGMSRecord> getRecords() {
return mRecords;
SparseArray<CGMSRecord> getRecords() {
return records;
}
/**
* Clears the records list locally
*/
public void clear() {
mRecords.clear();
mCallbacks.onDatasetCleared(getBluetoothDevice());
void clear() {
records.clear();
callbacks.onDataSetCleared(getBluetoothDevice());
}
/**
@@ -340,14 +349,14 @@ public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
* The data will be returned to Glucose Measurement characteristic as a notification followed by
* Record Access Control Point indication with status code Success or other in case of error.
*/
public void getLastRecord() {
if (mRecordAccessControlPointCharacteristic == null)
void getLastRecord() {
if (recordAccessControlPointCharacteristic == null)
return;
clear();
mCallbacks.onOperationStarted(getBluetoothDevice());
mRecordAccessRequestInProgress = true;
writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.reportLastStoredRecord())
callbacks.onOperationStarted(getBluetoothDevice());
recordAccessRequestInProgress = true;
writeCharacteristic(recordAccessControlPointCharacteristic, RecordAccessControlPointData.reportLastStoredRecord())
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
.enqueue();
}
@@ -357,14 +366,14 @@ public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
* The data will be returned to Glucose Measurement characteristic as a notification followed by
* Record Access Control Point indication with status code Success or other in case of error.
*/
public void getFirstRecord() {
if (mRecordAccessControlPointCharacteristic == null)
void getFirstRecord() {
if (recordAccessControlPointCharacteristic == null)
return;
clear();
mCallbacks.onOperationStarted(getBluetoothDevice());
mRecordAccessRequestInProgress = true;
writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.reportFirstStoredRecord())
callbacks.onOperationStarted(getBluetoothDevice());
recordAccessRequestInProgress = true;
writeCharacteristic(recordAccessControlPointCharacteristic, RecordAccessControlPointData.reportFirstStoredRecord())
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
.enqueue();
}
@@ -372,11 +381,11 @@ public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
/**
* Sends abort operation signal to the device.
*/
public void abort() {
if (mRecordAccessControlPointCharacteristic == null)
void abort() {
if (recordAccessControlPointCharacteristic == null)
return;
writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.abortOperation())
writeCharacteristic(recordAccessControlPointCharacteristic, RecordAccessControlPointData.abortOperation())
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
.enqueue();
}
@@ -387,14 +396,14 @@ public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
* The data will be returned to Glucose Measurement characteristic as a notification followed by
* Record Access Control Point indication with status code Success or other in case of error.
*/
public void getAllRecords() {
if (mRecordAccessControlPointCharacteristic == null)
void getAllRecords() {
if (recordAccessControlPointCharacteristic == null)
return;
clear();
mCallbacks.onOperationStarted(getBluetoothDevice());
mRecordAccessRequestInProgress = true;
writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.reportNumberOfAllStoredRecords())
callbacks.onOperationStarted(getBluetoothDevice());
recordAccessRequestInProgress = true;
writeCharacteristic(recordAccessControlPointCharacteristic, RecordAccessControlPointData.reportNumberOfAllStoredRecords())
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
.enqueue();
}
@@ -405,19 +414,19 @@ public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
* The data will be returned to Glucose Measurement characteristic as a notification followed by
* Record Access Control Point indication with status code Success or other in case of error.
*/
public void refreshRecords() {
if (mRecordAccessControlPointCharacteristic == null)
void refreshRecords() {
if (recordAccessControlPointCharacteristic == null)
return;
if (mRecords.size() == 0) {
if (records.size() == 0) {
getAllRecords();
} else {
mCallbacks.onOperationStarted(getBluetoothDevice());
callbacks.onOperationStarted(getBluetoothDevice());
// Obtain the last sequence number
final int sequenceNumber = mRecords.keyAt(mRecords.size() - 1) + 1;
mRecordAccessRequestInProgress = true;
writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.reportStoredRecordsGreaterThenOrEqualTo(sequenceNumber))
final int sequenceNumber = records.keyAt(records.size() - 1) + 1;
recordAccessRequestInProgress = true;
writeCharacteristic(recordAccessControlPointCharacteristic, RecordAccessControlPointData.reportStoredRecordsGreaterThenOrEqualTo(sequenceNumber))
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
.enqueue();
// Info:
@@ -431,13 +440,13 @@ public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
* This feature is not supported by the CGMS sample from the SDK, so monitor will answer with
* the Op Code Not Supported error.
*/
public void deleteAllRecords() {
if (mRecordAccessControlPointCharacteristic == null)
void deleteAllRecords() {
if (recordAccessControlPointCharacteristic == null)
return;
clear();
mCallbacks.onOperationStarted(getBluetoothDevice());
writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.deleteAllStoredRecords())
callbacks.onOperationStarted(getBluetoothDevice());
writeCharacteristic(recordAccessControlPointCharacteristic, RecordAccessControlPointData.deleteAllStoredRecords())
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
.enqueue();
}

View File

@@ -27,9 +27,9 @@ import androidx.annotation.NonNull;
import no.nordicsemi.android.nrftoolbox.battery.BatteryManagerCallbacks;
public interface CGMSManagerCallbacks extends BatteryManagerCallbacks {
interface CGMSManagerCallbacks extends BatteryManagerCallbacks {
void onCGMValueReceived(@NonNull final BluetoothDevice device, final CGMSRecord record);
void onCGMValueReceived(@NonNull final BluetoothDevice device, @NonNull final CGMSRecord record);
void onOperationStarted(final @NonNull BluetoothDevice device);
@@ -41,7 +41,7 @@ public interface CGMSManagerCallbacks extends BatteryManagerCallbacks {
void onOperationNotSupported(final @NonNull BluetoothDevice device);
void onDatasetCleared(final @NonNull BluetoothDevice device);
void onDataSetCleared(final @NonNull BluetoothDevice device);
void onNumberOfRecordsRequested(final @NonNull BluetoothDevice device, final int value);

View File

@@ -5,11 +5,11 @@ import android.os.Parcelable;
class CGMSRecord implements Parcelable{
/** Record sequence number. */
protected int sequenceNumber;
int sequenceNumber;
/** The base time of the measurement (start time + sequenceNumber of minutes). */
protected long timestamp;
long timestamp;
/** The glucose concentration in mg/dL. */
protected float glucoseConcentration;
float glucoseConcentration;
CGMSRecord(final int sequenceNumber, final float glucoseConcentration, final long timestamp) {
this.sequenceNumber = sequenceNumber;

View File

@@ -13,62 +13,65 @@ import java.util.Date;
import java.util.List;
import java.util.Locale;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import no.nordicsemi.android.nrftoolbox.R;
public class CGMSRecordsAdapter extends BaseAdapter {
private final static SimpleDateFormat mTimeFormat = new SimpleDateFormat("dd.MM.yyyy HH:mm", Locale.US);
class CGMSRecordsAdapter extends BaseAdapter {
private final static SimpleDateFormat timeFormat = new SimpleDateFormat("dd.MM.yyyy HH:mm", Locale.US);
private List<CGMSRecord> mRecords;
private LayoutInflater mInflater;
private List<CGMSRecord> records;
private LayoutInflater inflater;
public CGMSRecordsAdapter(final Context context) {
mRecords = new ArrayList<>();
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
CGMSRecordsAdapter(@NonNull final Context context) {
records = new ArrayList<>();
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public int getCount() {
return mRecords.size();
return records.size();
}
@Override
public Object getItem(int i) {
public Object getItem(final int i) {
return null;
}
@Override
public long getItemId(int i) {
public long getItemId(final int i) {
return i;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
public View getView(final int position, @Nullable final View convertView, @NonNull final ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.activity_feature_cgms_item, parent, false);
View view = convertView;
if (view == null) {
view = inflater.inflate(R.layout.activity_feature_cgms_item, parent, false);
viewHolder = new ViewHolder();
viewHolder.concentration = convertView.findViewById(R.id.cgms_concentration);
viewHolder.time = convertView.findViewById(R.id.time);
viewHolder.details = convertView.findViewById(R.id.details);
convertView.setTag(viewHolder);
viewHolder.concentration = view.findViewById(R.id.cgms_concentration);
viewHolder.time = view.findViewById(R.id.time);
viewHolder.details = view.findViewById(R.id.details);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
viewHolder = (ViewHolder) view.getTag();
}
final CGMSRecord cgmsRecord = mRecords.get(position);
final CGMSRecord cgmsRecord = records.get(position);
viewHolder.concentration.setText(String.valueOf(cgmsRecord.glucoseConcentration));
viewHolder.details.setText(viewHolder.details.getResources().getString(R.string.cgms_details, cgmsRecord.sequenceNumber));
viewHolder.time.setText(mTimeFormat.format(new Date(cgmsRecord.timestamp)));
viewHolder.time.setText(timeFormat.format(new Date(cgmsRecord.timestamp)));
return convertView;
return view;
}
public void addItem(final CGMSRecord record) {
mRecords.add(record);
void addItem(final CGMSRecord record) {
records.add(record);
}
public void clear() {
mRecords.clear();
void clear() {
records.clear();
}
private static class ViewHolder {

View File

@@ -42,29 +42,29 @@ public class CGMService extends BleProfileService implements CGMSManagerCallback
private final static int OPEN_ACTIVITY_REQ = 0;
private final static int DISCONNECT_REQ = 1;
private CGMSManager mManager;
private final LocalBinder mBinder = new CGMSBinder();
private CGMSManager manager;
private final LocalBinder binder = new CGMSBinder();
/**
* This local binder is an interface for the bonded activity to operate with the RSC sensor
*/
public class CGMSBinder extends LocalBinder {
class CGMSBinder extends LocalBinder {
/**
* Returns all records as a sparse array where sequence number is the key.
*
* @return the records list
*/
public SparseArray<CGMSRecord> getRecords() {
return mManager.getRecords();
SparseArray<CGMSRecord> getRecords() {
return manager.getRecords();
}
/**
* Clears the records list locally
*/
public void clear() {
if (mManager != null)
mManager.clear();
void clear() {
if (manager != null)
manager.clear();
}
/**
@@ -72,9 +72,9 @@ public class CGMService extends BleProfileService implements CGMSManagerCallback
* The data will be returned to Glucose Measurement characteristic as a notification followed by Record Access Control
* Point indication with status code ({@link CGMSManager# RESPONSE_SUCCESS} or other in case of error.
*/
public void getFirstRecord() {
if (mManager != null)
mManager.getFirstRecord();
void getFirstRecord() {
if (manager != null)
manager.getFirstRecord();
}
/**
@@ -82,9 +82,9 @@ public class CGMService extends BleProfileService implements CGMSManagerCallback
* The data will be returned to Glucose Measurement characteristic as a notification followed by Record Access
* Control Point indication with status code Success or other in case of error.
*/
public void getLastRecord() {
if (mManager != null)
mManager.getLastRecord();
void getLastRecord() {
if (manager != null)
manager.getLastRecord();
}
/**
@@ -93,9 +93,9 @@ public class CGMService extends BleProfileService implements CGMSManagerCallback
* The data will be returned to Glucose Measurement characteristic as a series of notifications followed
* by Record Access Control Point indication with status code Success or other in case of error.
*/
public void getAllRecords() {
if (mManager != null)
mManager.getAllRecords();
void getAllRecords() {
if (manager != null)
manager.getAllRecords();
}
/**
@@ -104,36 +104,36 @@ public class CGMService extends BleProfileService implements CGMSManagerCallback
* characteristic as a series of notifications followed by Record Access Control Point
* indication with status code Success or other in case of error.
*/
public void refreshRecords() {
if (mManager != null)
mManager.refreshRecords();
void refreshRecords() {
if (manager != null)
manager.refreshRecords();
}
/**
* Sends abort operation signal to the device
*/
public void abort() {
if (mManager != null)
mManager.abort();
void abort() {
if (manager != null)
manager.abort();
}
/**
* Sends Delete op code with All stored records parameter. This method may not be supported by the SDK sample.
*/
public void deleteAllRecords() {
if (mManager != null)
mManager.deleteAllRecords();
void deleteAllRecords() {
if (manager != null)
manager.deleteAllRecords();
}
}
@Override
protected LocalBinder getBinder() {
return mBinder;
return binder;
}
@Override
protected LoggableBleManager<CGMSManagerCallbacks> initializeManager() {
return mManager = new CGMSManager(this);
return manager = new CGMSManager(this);
}
@@ -142,14 +142,14 @@ public class CGMService extends BleProfileService implements CGMSManagerCallback
super.onCreate();
final IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_DISCONNECT);
registerReceiver(mDisconnectActionBroadcastReceiver, filter);
registerReceiver(disconnectActionBroadcastReceiver, filter);
}
@Override
public void onDestroy() {
// when user has disconnected from the sensor, we have to cancel the notification that we've created some milliseconds before using unbindService
stopForegroundService();
unregisterReceiver(mDisconnectActionBroadcastReceiver);
unregisterReceiver(disconnectActionBroadcastReceiver);
super.onDestroy();
}
@@ -199,6 +199,7 @@ public class CGMService extends BleProfileService implements CGMSManagerCallback
* f.e. <code>&lt;string name="name"&gt;%s is connected&lt;/string&gt;</code>
* @param defaults signals that will be used to notify the user
*/
@SuppressWarnings("SameParameterValue")
private Notification createNotification(final int messageResId, final int defaults) {
final Intent parentIntent = new Intent(this, FeaturesActivity.class);
parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -230,7 +231,7 @@ public class CGMService extends BleProfileService implements CGMSManagerCallback
/**
* This broadcast receiver listens for {@link #ACTION_DISCONNECT} that may be fired by pressing Disconnect action button on the notification.
*/
private final BroadcastReceiver mDisconnectActionBroadcastReceiver = new BroadcastReceiver() {
private final BroadcastReceiver disconnectActionBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
Logger.i(getLogSession(), "[Notification] Disconnect action pressed");
@@ -242,7 +243,7 @@ public class CGMService extends BleProfileService implements CGMSManagerCallback
};
@Override
public void onCGMValueReceived(@NonNull final BluetoothDevice device, final CGMSRecord record) {
public void onCGMValueReceived(@NonNull final BluetoothDevice device, @NonNull final CGMSRecord record) {
final Intent broadcast = new Intent(BROADCAST_NEW_CGMS_VALUE);
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
broadcast.putExtra(EXTRA_CGMS_RECORD, record);
@@ -290,7 +291,7 @@ public class CGMService extends BleProfileService implements CGMSManagerCallback
}
@Override
public void onDatasetCleared(@NonNull final BluetoothDevice device) {
public void onDataSetCleared(@NonNull final BluetoothDevice device) {
final Intent broadcast = new Intent(BROADCAST_DATA_SET_CLEAR);
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);

View File

@@ -30,6 +30,8 @@ import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import androidx.annotation.NonNull;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import android.view.Menu;
import android.widget.TextView;
@@ -44,15 +46,15 @@ import no.nordicsemi.android.nrftoolbox.profile.BleProfileService;
import no.nordicsemi.android.nrftoolbox.profile.BleProfileServiceReadyActivity;
public class CSCActivity extends BleProfileServiceReadyActivity<CSCService.CSCBinder> {
private TextView mSpeedView;
private TextView mSpeedUnitView;
private TextView mCadenceView;
private TextView mDistanceView;
private TextView mDistanceUnitView;
private TextView mTotalDistanceView;
private TextView mTotalDistanceUnitView;
private TextView mGearRatioView;
private TextView mBatteryLevelView;
private TextView speedView;
private TextView speedUnitView;
private TextView cadenceView;
private TextView distanceView;
private TextView distanceUnitView;
private TextView totalDistanceView;
private TextView totalDistanceUnitView;
private TextView gearRatioView;
private TextView batteryLevelView;
@Override
protected void onCreateView(final Bundle savedInstanceState) {
@@ -62,25 +64,25 @@ public class CSCActivity extends BleProfileServiceReadyActivity<CSCService.CSCBi
@Override
protected void onInitialize(final Bundle savedInstanceState) {
LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, makeIntentFilter());
LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, makeIntentFilter());
}
@Override
protected void onDestroy() {
super.onDestroy();
LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver);
LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver);
}
private void setGui() {
mSpeedView = findViewById(R.id.speed);
mSpeedUnitView = findViewById(R.id.speed_unit);
mCadenceView = findViewById(R.id.cadence);
mDistanceView = findViewById(R.id.distance);
mDistanceUnitView = findViewById(R.id.distance_unit);
mTotalDistanceView = findViewById(R.id.distance_total);
mTotalDistanceUnitView = findViewById(R.id.distance_total_unit);
mGearRatioView = findViewById(R.id.ratio);
mBatteryLevelView = findViewById(R.id.battery);
speedView = findViewById(R.id.speed);
speedUnitView = findViewById(R.id.speed_unit);
cadenceView = findViewById(R.id.cadence);
distanceView = findViewById(R.id.distance);
distanceUnitView = findViewById(R.id.distance_unit);
totalDistanceView = findViewById(R.id.distance_total);
totalDistanceUnitView = findViewById(R.id.distance_total_unit);
gearRatioView = findViewById(R.id.ratio);
batteryLevelView = findViewById(R.id.battery);
}
@Override
@@ -91,12 +93,12 @@ public class CSCActivity extends BleProfileServiceReadyActivity<CSCService.CSCBi
@Override
protected void setDefaultUI() {
mSpeedView.setText(R.string.not_available_value);
mCadenceView.setText(R.string.not_available_value);
mDistanceView.setText(R.string.not_available_value);
mTotalDistanceView.setText(R.string.not_available_value);
mGearRatioView.setText(R.string.not_available_value);
mBatteryLevelView.setText(R.string.not_available);
speedView.setText(R.string.not_available_value);
cadenceView.setText(R.string.not_available_value);
distanceView.setText(R.string.not_available_value);
totalDistanceView.setText(R.string.not_available_value);
gearRatioView.setText(R.string.not_available_value);
batteryLevelView.setText(R.string.not_available);
setUnits();
}
@@ -107,19 +109,19 @@ public class CSCActivity extends BleProfileServiceReadyActivity<CSCService.CSCBi
switch (unit) {
case SettingsFragment.SETTINGS_UNIT_M_S: // [m/s]
mSpeedUnitView.setText(R.string.csc_speed_unit_m_s);
mDistanceUnitView.setText(R.string.csc_distance_unit_m);
mTotalDistanceUnitView.setText(R.string.csc_total_distance_unit_km);
speedUnitView.setText(R.string.csc_speed_unit_m_s);
distanceUnitView.setText(R.string.csc_distance_unit_m);
totalDistanceUnitView.setText(R.string.csc_total_distance_unit_km);
break;
case SettingsFragment.SETTINGS_UNIT_KM_H: // [km/h]
mSpeedUnitView.setText(R.string.csc_speed_unit_km_h);
mDistanceUnitView.setText(R.string.csc_distance_unit_m);
mTotalDistanceUnitView.setText(R.string.csc_total_distance_unit_km);
speedUnitView.setText(R.string.csc_speed_unit_km_h);
distanceUnitView.setText(R.string.csc_distance_unit_m);
totalDistanceUnitView.setText(R.string.csc_total_distance_unit_km);
break;
case SettingsFragment.SETTINGS_UNIT_MPH: // [mph]
mSpeedUnitView.setText(R.string.csc_speed_unit_mph);
mDistanceUnitView.setText(R.string.csc_distance_unit_yd);
mTotalDistanceUnitView.setText(R.string.csc_total_distance_unit_mile);
speedUnitView.setText(R.string.csc_speed_unit_mph);
distanceUnitView.setText(R.string.csc_distance_unit_yd);
totalDistanceUnitView.setText(R.string.csc_total_distance_unit_mile);
break;
}
}
@@ -177,14 +179,14 @@ public class CSCActivity extends BleProfileServiceReadyActivity<CSCService.CSCBi
}
@Override
public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) {
public void onServicesDiscovered(@NonNull final BluetoothDevice device, final boolean optionalServicesFound) {
// not used
}
@Override
public void onDeviceDisconnected(final BluetoothDevice device) {
public void onDeviceDisconnected(@NonNull final BluetoothDevice device) {
super.onDeviceDisconnected(device);
mBatteryLevelView.setText(R.string.not_available);
batteryLevelView.setText(R.string.not_available);
}
private void onMeasurementReceived(final BluetoothDevice device, float speed, float distance, float totalDistance) {
@@ -197,42 +199,42 @@ public class CSCActivity extends BleProfileServiceReadyActivity<CSCService.CSCBi
// pass through intended
case SettingsFragment.SETTINGS_UNIT_M_S:
if (distance < 1000) { // 1 km in m
mDistanceView.setText(String.format(Locale.US, "%.0f", distance));
mDistanceUnitView.setText(R.string.csc_distance_unit_m);
distanceView.setText(String.format(Locale.US, "%.0f", distance));
distanceUnitView.setText(R.string.csc_distance_unit_m);
} else {
mDistanceView.setText(String.format(Locale.US, "%.2f", distance / 1000.0f));
mDistanceUnitView.setText(R.string.csc_distance_unit_km);
distanceView.setText(String.format(Locale.US, "%.2f", distance / 1000.0f));
distanceUnitView.setText(R.string.csc_distance_unit_km);
}
mTotalDistanceView.setText(String.format(Locale.US, "%.2f", totalDistance / 1000.0f));
totalDistanceView.setText(String.format(Locale.US, "%.2f", totalDistance / 1000.0f));
break;
case SettingsFragment.SETTINGS_UNIT_MPH:
speed = speed * 2.2369f;
if (distance < 1760) { // 1 mile in yrs
mDistanceView.setText(String.format(Locale.US, "%.0f", distance));
mDistanceUnitView.setText(R.string.csc_distance_unit_yd);
distanceView.setText(String.format(Locale.US, "%.0f", distance));
distanceUnitView.setText(R.string.csc_distance_unit_yd);
} else {
mDistanceView.setText(String.format(Locale.US, "%.2f", distance / 1760.0f));
mDistanceUnitView.setText(R.string.csc_distance_unit_mile);
distanceView.setText(String.format(Locale.US, "%.2f", distance / 1760.0f));
distanceUnitView.setText(R.string.csc_distance_unit_mile);
}
mTotalDistanceView.setText(String.format(Locale.US, "%.2f", totalDistance / 1609.31f));
totalDistanceView.setText(String.format(Locale.US, "%.2f", totalDistance / 1609.31f));
break;
}
mSpeedView.setText(String.format(Locale.US, "%.1f", speed));
speedView.setText(String.format(Locale.US, "%.1f", speed));
}
private void onGearRatioUpdate(final BluetoothDevice device, final int cadence, final float ratio) {
mCadenceView.setText(String.format(Locale.US, "%d", cadence));
mGearRatioView.setText(String.format(Locale.US, "%.1f", ratio));
cadenceView.setText(String.format(Locale.US, "%d", cadence));
gearRatioView.setText(String.format(Locale.US, "%.1f", ratio));
}
public void onBatteryLevelChanged(final BluetoothDevice device, final int value) {
mBatteryLevelView.setText(getString(R.string.battery, value));
batteryLevelView.setText(getString(R.string.battery, value));
}
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
final String action = intent.getAction();

View File

@@ -29,6 +29,8 @@ import android.bluetooth.BluetoothGattService;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import androidx.annotation.FloatRange;
import androidx.annotation.NonNull;
import android.util.Log;
@@ -43,12 +45,12 @@ import no.nordicsemi.android.nrftoolbox.parser.CSCMeasurementParser;
public class CSCManager extends BatteryManager<CSCManagerCallbacks> {
/** Cycling Speed and Cadence service UUID. */
public final static UUID CYCLING_SPEED_AND_CADENCE_SERVICE_UUID = UUID.fromString("00001816-0000-1000-8000-00805f9b34fb");
final static UUID CYCLING_SPEED_AND_CADENCE_SERVICE_UUID = UUID.fromString("00001816-0000-1000-8000-00805f9b34fb");
/** Cycling Speed and Cadence Measurement characteristic UUID. */
private final static UUID CSC_MEASUREMENT_CHARACTERISTIC_UUID = UUID.fromString("00002A5B-0000-1000-8000-00805f9b34fb");
private final SharedPreferences preferences;
private BluetoothGattCharacteristic mCSCMeasurementCharacteristic;
private BluetoothGattCharacteristic cscMeasurementCharacteristic;
CSCManager(final Context context) {
super(context);
@@ -58,21 +60,21 @@ public class CSCManager extends BatteryManager<CSCManagerCallbacks> {
@NonNull
@Override
protected BatteryManagerGattCallback getGattCallback() {
return mGattCallback;
return gattCallback;
}
/**
* BluetoothGatt callbacks for connection/disconnection, service discovery,
* receiving indication, etc.
*/
private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() {
private final BatteryManagerGattCallback gattCallback = new BatteryManagerGattCallback() {
@Override
protected void initialize() {
super.initialize();
// CSC characteristic is required
setNotificationCallback(mCSCMeasurementCharacteristic)
setNotificationCallback(cscMeasurementCharacteristic)
.with(new CyclingSpeedAndCadenceMeasurementDataCallback() {
@Override
public void onDataReceived(@NonNull final BluetoothDevice device, final @NonNull Data data) {
@@ -90,38 +92,41 @@ public class CSCManager extends BatteryManager<CSCManagerCallbacks> {
@Override
public void onDistanceChanged(@NonNull final BluetoothDevice device,
final float totalDistance, final float distance, final float speed) {
mCallbacks.onDistanceChanged(device, totalDistance, distance, speed);
@FloatRange(from = 0) final float totalDistance,
@FloatRange(from = 0) final float distance,
@FloatRange(from = 0) final float speed) {
callbacks.onDistanceChanged(device, totalDistance, distance, speed);
}
@Override
public void onCrankDataChanged(@NonNull final BluetoothDevice device,
final float crankCadence, final float gearRatio) {
mCallbacks.onCrankDataChanged(device, crankCadence, gearRatio);
@FloatRange(from = 0) final float crankCadence,
final float gearRatio) {
callbacks.onCrankDataChanged(device, crankCadence, gearRatio);
}
@Override
public void onInvalidDataReceived(@NonNull final BluetoothDevice device,
final @NonNull Data data) {
@NonNull final Data data) {
log(Log.WARN, "Invalid CSC Measurement data received: " + data);
}
});
enableNotifications(mCSCMeasurementCharacteristic).enqueue();
enableNotifications(cscMeasurementCharacteristic).enqueue();
}
@Override
public boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) {
final BluetoothGattService service = gatt.getService(CYCLING_SPEED_AND_CADENCE_SERVICE_UUID);
if (service != null) {
mCSCMeasurementCharacteristic = service.getCharacteristic(CSC_MEASUREMENT_CHARACTERISTIC_UUID);
cscMeasurementCharacteristic = service.getCharacteristic(CSC_MEASUREMENT_CHARACTERISTIC_UUID);
}
return mCSCMeasurementCharacteristic != null;
return cscMeasurementCharacteristic != null;
}
@Override
protected void onDeviceDisconnected() {
super.onDeviceDisconnected();
mCSCMeasurementCharacteristic = null;
cscMeasurementCharacteristic = null;
}
};
}

View File

@@ -73,8 +73,8 @@ public class CSCService extends BleProfileService implements CSCManagerCallbacks
private final static int OPEN_ACTIVITY_REQ = 0;
private final static int DISCONNECT_REQ = 1;
private final LocalBinder mBinder = new CSCBinder();
private CSCManager mManager;
private final LocalBinder binder = new CSCBinder();
private CSCManager manager;
/**
* This local binder is an interface for the bonded activity to operate with the RSC sensor
@@ -85,12 +85,12 @@ public class CSCService extends BleProfileService implements CSCManagerCallbacks
@Override
protected LocalBinder getBinder() {
return mBinder;
return binder;
}
@Override
protected LoggableBleManager<CSCManagerCallbacks> initializeManager() {
return mManager = new CSCManager(this);
return manager = new CSCManager(this);
}
@Override
@@ -99,14 +99,14 @@ public class CSCService extends BleProfileService implements CSCManagerCallbacks
final IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_DISCONNECT);
registerReceiver(mDisconnectActionBroadcastReceiver, filter);
registerReceiver(disconnectActionBroadcastReceiver, filter);
}
@Override
public void onDestroy() {
// when user has disconnected from the sensor, we have to cancel the notification that we've created some milliseconds before using unbindService
cancelNotification();
unregisterReceiver(mDisconnectActionBroadcastReceiver);
unregisterReceiver(disconnectActionBroadcastReceiver);
super.onDestroy();
}
@@ -118,7 +118,7 @@ public class CSCService extends BleProfileService implements CSCManagerCallbacks
if (isConnected()) {
// This method will read the Battery Level value, if possible and then try to enable battery notifications (if it has NOTIFY property).
// If the Battery Level characteristic has only the NOTIFY property, it will only try to enable notifications.
mManager.readBatteryLevelCharacteristic();
manager.readBatteryLevelCharacteristic();
}
}
@@ -127,7 +127,7 @@ public class CSCService extends BleProfileService implements CSCManagerCallbacks
// When we are connected, but the application is not open, we are not really interested in battery level notifications.
// But we will still be receiving other values, if enabled.
if (isConnected())
mManager.disableBatteryLevelCharacteristicNotifications();
manager.disableBatteryLevelCharacteristicNotifications();
startForegroundService();
}
@@ -193,6 +193,7 @@ public class CSCService extends BleProfileService implements CSCManagerCallbacks
* f.e. <code>&lt;string name="name"&gt;%s is connected&lt;/string&gt;</code>
* @param defaults
*/
@SuppressWarnings("SameParameterValue")
private Notification createNotification(final int messageResId, final int defaults) {
final Intent parentIntent = new Intent(this, FeaturesActivity.class);
parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -224,7 +225,7 @@ public class CSCService extends BleProfileService implements CSCManagerCallbacks
/**
* This broadcast receiver listens for {@link #ACTION_DISCONNECT} that may be fired by pressing Disconnect action button on the notification.
*/
private final BroadcastReceiver mDisconnectActionBroadcastReceiver = new BroadcastReceiver() {
private final BroadcastReceiver disconnectActionBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
Logger.i(getLogSession(), "[Notification] Disconnect action pressed");

View File

@@ -111,33 +111,33 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
private static final int SELECT_FILE_REQ = 1;
private static final int SELECT_INIT_FILE_REQ = 2;
private TextView mDeviceNameView;
private TextView mFileNameView;
private TextView mFileTypeView;
private TextView mFileScopeView;
private TextView mFileSizeView;
private TextView mFileStatusView;
private TextView mTextPercentage;
private TextView mTextUploading;
private ProgressBar mProgressBar;
private TextView deviceNameView;
private TextView fileNameView;
private TextView fileTypeView;
private TextView fileScopeView;
private TextView fileSizeView;
private TextView fileStatusView;
private TextView textPercentage;
private TextView textUploading;
private ProgressBar progressBar;
private Button mSelectFileButton, mUploadButton, mConnectButton;
private Button selectFileButton, uploadButton, connectButton;
private BluetoothDevice mSelectedDevice;
private String mFilePath;
private Uri mFileStreamUri;
private String mInitFilePath;
private Uri mInitFileStreamUri;
private int mFileType;
private int mFileTypeTmp; // This value is being used when user is selecting a file not to overwrite the old value (in case he/she will cancel selecting file)
private Integer mScope;
private boolean mStatusOk;
private BluetoothDevice selectedDevice;
private String filePath;
private Uri fileStreamUri;
private String initFilePath;
private Uri initFileStreamUri;
private int fileType;
private int fileTypeTmp; // This value is being used when user is selecting a file not to overwrite the old value (in case he/she will cancel selecting file)
private Integer scope;
private boolean statusOk;
/** Flag set to true in {@link #onRestart()} and to false in {@link #onPause()}. */
private boolean mResumed;
/** Flag set to true if DFU operation was completed while {@link #mResumed} was false. */
private boolean mDfuCompleted;
/** The error message received from DFU service while {@link #mResumed} was false. */
private String mDfuError;
private boolean resumed;
/** Flag set to true if DFU operation was completed while {@link #resumed} was false. */
private boolean dfuCompleted;
/** The error message received from DFU service while {@link #resumed} was false. */
private String dfuError;
/**
* The progress listener receives events from the DFU Service.
@@ -146,41 +146,41 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
* correct information after user comes back to the activity and this information can't be read from the service
* as it might have been killed already (DFU completed or finished with error).
*/
private final DfuProgressListener mDfuProgressListener = new DfuProgressListenerAdapter() {
private final DfuProgressListener dfuProgressListener = new DfuProgressListenerAdapter() {
@Override
public void onDeviceConnecting(final String deviceAddress) {
mProgressBar.setIndeterminate(true);
mTextPercentage.setText(R.string.dfu_status_connecting);
public void onDeviceConnecting(@NonNull final String deviceAddress) {
progressBar.setIndeterminate(true);
textPercentage.setText(R.string.dfu_status_connecting);
}
@Override
public void onDfuProcessStarting(final String deviceAddress) {
mProgressBar.setIndeterminate(true);
mTextPercentage.setText(R.string.dfu_status_starting);
public void onDfuProcessStarting(@NonNull final String deviceAddress) {
progressBar.setIndeterminate(true);
textPercentage.setText(R.string.dfu_status_starting);
}
@Override
public void onEnablingDfuMode(final String deviceAddress) {
mProgressBar.setIndeterminate(true);
mTextPercentage.setText(R.string.dfu_status_switching_to_dfu);
public void onEnablingDfuMode(@NonNull final String deviceAddress) {
progressBar.setIndeterminate(true);
textPercentage.setText(R.string.dfu_status_switching_to_dfu);
}
@Override
public void onFirmwareValidating(final String deviceAddress) {
mProgressBar.setIndeterminate(true);
mTextPercentage.setText(R.string.dfu_status_validating);
public void onFirmwareValidating(@NonNull final String deviceAddress) {
progressBar.setIndeterminate(true);
textPercentage.setText(R.string.dfu_status_validating);
}
@Override
public void onDeviceDisconnecting(final String deviceAddress) {
mProgressBar.setIndeterminate(true);
mTextPercentage.setText(R.string.dfu_status_disconnecting);
public void onDeviceDisconnecting(@NonNull final String deviceAddress) {
progressBar.setIndeterminate(true);
textPercentage.setText(R.string.dfu_status_disconnecting);
}
@Override
public void onDfuCompleted(final String deviceAddress) {
mTextPercentage.setText(R.string.dfu_status_completed);
if (mResumed) {
public void onDfuCompleted(@NonNull final String deviceAddress) {
textPercentage.setText(R.string.dfu_status_completed);
if (resumed) {
// let's wait a bit until we cancel the notification. When canceled immediately it will be recreated by service again.
new Handler().postDelayed(() -> {
onTransferCompleted();
@@ -191,13 +191,13 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
}, 200);
} else {
// Save that the DFU process has finished
mDfuCompleted = true;
dfuCompleted = true;
}
}
@Override
public void onDfuAborted(final String deviceAddress) {
mTextPercentage.setText(R.string.dfu_status_aborted);
public void onDfuAborted(@NonNull final String deviceAddress) {
textPercentage.setText(R.string.dfu_status_aborted);
// let's wait a bit until we cancel the notification. When canceled immediately it will be recreated by service again.
new Handler().postDelayed(() -> {
onUploadCanceled();
@@ -209,19 +209,21 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
}
@Override
public void onProgressChanged(final String deviceAddress, final int percent, final float speed, final float avgSpeed, final int currentPart, final int partsTotal) {
mProgressBar.setIndeterminate(false);
mProgressBar.setProgress(percent);
mTextPercentage.setText(getString(R.string.dfu_uploading_percentage, percent));
public void onProgressChanged(@NonNull final String deviceAddress, final int percent,
final float speed, final float avgSpeed,
final int currentPart, final int partsTotal) {
progressBar.setIndeterminate(false);
progressBar.setProgress(percent);
textPercentage.setText(getString(R.string.dfu_uploading_percentage, percent));
if (partsTotal > 1)
mTextUploading.setText(getString(R.string.dfu_status_uploading_part, currentPart, partsTotal));
textUploading.setText(getString(R.string.dfu_status_uploading_part, currentPart, partsTotal));
else
mTextUploading.setText(R.string.dfu_status_uploading);
textUploading.setText(R.string.dfu_status_uploading);
}
@Override
public void onError(final String deviceAddress, final int error, final int errorType, final String message) {
if (mResumed) {
public void onError(@NonNull final String deviceAddress, final int error, final int errorType, final String message) {
if (resumed) {
showErrorMessage(message);
// We have to wait a bit before canceling notification. This is called before DfuService creates the last notification.
@@ -231,7 +233,7 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
manager.cancel(DfuService.NOTIFICATION_ID);
}, 200);
} else {
mDfuError = message;
dfuError = message;
}
}
};
@@ -257,45 +259,45 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
}
// restore saved state
mFileType = DfuService.TYPE_AUTO; // Default
fileType = DfuService.TYPE_AUTO; // Default
if (savedInstanceState != null) {
mFileType = savedInstanceState.getInt(DATA_FILE_TYPE);
mFileTypeTmp = savedInstanceState.getInt(DATA_FILE_TYPE_TMP);
mFilePath = savedInstanceState.getString(DATA_FILE_PATH);
mFileStreamUri = savedInstanceState.getParcelable(DATA_FILE_STREAM);
mInitFilePath = savedInstanceState.getString(DATA_INIT_FILE_PATH);
mInitFileStreamUri = savedInstanceState.getParcelable(DATA_INIT_FILE_STREAM);
mSelectedDevice = savedInstanceState.getParcelable(DATA_DEVICE);
mStatusOk = mStatusOk || savedInstanceState.getBoolean(DATA_STATUS);
mScope = savedInstanceState.containsKey(DATA_SCOPE) ? savedInstanceState.getInt(DATA_SCOPE) : null;
mUploadButton.setEnabled(mSelectedDevice != null && mStatusOk);
mDfuCompleted = savedInstanceState.getBoolean(DATA_DFU_COMPLETED);
mDfuError = savedInstanceState.getString(DATA_DFU_ERROR);
fileType = savedInstanceState.getInt(DATA_FILE_TYPE);
fileTypeTmp = savedInstanceState.getInt(DATA_FILE_TYPE_TMP);
filePath = savedInstanceState.getString(DATA_FILE_PATH);
fileStreamUri = savedInstanceState.getParcelable(DATA_FILE_STREAM);
initFilePath = savedInstanceState.getString(DATA_INIT_FILE_PATH);
initFileStreamUri = savedInstanceState.getParcelable(DATA_INIT_FILE_STREAM);
selectedDevice = savedInstanceState.getParcelable(DATA_DEVICE);
statusOk = statusOk || savedInstanceState.getBoolean(DATA_STATUS);
scope = savedInstanceState.containsKey(DATA_SCOPE) ? savedInstanceState.getInt(DATA_SCOPE) : null;
uploadButton.setEnabled(selectedDevice != null && statusOk);
dfuCompleted = savedInstanceState.getBoolean(DATA_DFU_COMPLETED);
dfuError = savedInstanceState.getString(DATA_DFU_ERROR);
}
DfuServiceListenerHelper.registerProgressListener(this, mDfuProgressListener);
DfuServiceListenerHelper.registerProgressListener(this, dfuProgressListener);
}
@Override
protected void onDestroy() {
super.onDestroy();
DfuServiceListenerHelper.unregisterProgressListener(this, mDfuProgressListener);
DfuServiceListenerHelper.unregisterProgressListener(this, dfuProgressListener);
}
@Override
protected void onSaveInstanceState(final Bundle outState) {
protected void onSaveInstanceState(@NonNull final Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(DATA_FILE_TYPE, mFileType);
outState.putInt(DATA_FILE_TYPE_TMP, mFileTypeTmp);
outState.putString(DATA_FILE_PATH, mFilePath);
outState.putParcelable(DATA_FILE_STREAM, mFileStreamUri);
outState.putString(DATA_INIT_FILE_PATH, mInitFilePath);
outState.putParcelable(DATA_INIT_FILE_STREAM, mInitFileStreamUri);
outState.putParcelable(DATA_DEVICE, mSelectedDevice);
outState.putBoolean(DATA_STATUS, mStatusOk);
if (mScope != null) outState.putInt(DATA_SCOPE, mScope);
outState.putBoolean(DATA_DFU_COMPLETED, mDfuCompleted);
outState.putString(DATA_DFU_ERROR, mDfuError);
outState.putInt(DATA_FILE_TYPE, fileType);
outState.putInt(DATA_FILE_TYPE_TMP, fileTypeTmp);
outState.putString(DATA_FILE_PATH, filePath);
outState.putParcelable(DATA_FILE_STREAM, fileStreamUri);
outState.putString(DATA_INIT_FILE_PATH, initFilePath);
outState.putParcelable(DATA_INIT_FILE_STREAM, initFileStreamUri);
outState.putParcelable(DATA_DEVICE, selectedDevice);
outState.putBoolean(DATA_STATUS, statusOk);
if (scope != null) outState.putInt(DATA_SCOPE, scope);
outState.putBoolean(DATA_DFU_COMPLETED, dfuCompleted);
outState.putString(DATA_DFU_ERROR, dfuError);
}
private void setGUI() {
@@ -303,29 +305,29 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
mDeviceNameView = findViewById(R.id.device_name);
mFileNameView = findViewById(R.id.file_name);
mFileTypeView = findViewById(R.id.file_type);
mFileScopeView = findViewById(R.id.file_scope);
mFileSizeView = findViewById(R.id.file_size);
mFileStatusView = findViewById(R.id.file_status);
mSelectFileButton = findViewById(R.id.action_select_file);
mUploadButton = findViewById(R.id.action_upload);
mConnectButton = findViewById(R.id.action_connect);
mTextPercentage = findViewById(R.id.textviewProgress);
mTextUploading = findViewById(R.id.textviewUploading);
mProgressBar = findViewById(R.id.progressbar_file);
deviceNameView = findViewById(R.id.device_name);
fileNameView = findViewById(R.id.file_name);
fileTypeView = findViewById(R.id.file_type);
fileScopeView = findViewById(R.id.file_scope);
fileSizeView = findViewById(R.id.file_size);
fileStatusView = findViewById(R.id.file_status);
selectFileButton = findViewById(R.id.action_select_file);
uploadButton = findViewById(R.id.action_upload);
connectButton = findViewById(R.id.action_connect);
textPercentage = findViewById(R.id.textviewProgress);
textUploading = findViewById(R.id.textviewUploading);
progressBar = findViewById(R.id.progressbar_file);
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
if (isDfuServiceRunning()) {
// Restore image file information
mDeviceNameView.setText(preferences.getString(PREFS_DEVICE_NAME, ""));
mFileNameView.setText(preferences.getString(PREFS_FILE_NAME, ""));
mFileTypeView.setText(preferences.getString(PREFS_FILE_TYPE, ""));
mFileScopeView.setText(preferences.getString(PREFS_FILE_SCOPE, ""));
mFileSizeView.setText(preferences.getString(PREFS_FILE_SIZE, ""));
mFileStatusView.setText(R.string.dfu_file_status_ok);
mStatusOk = true;
deviceNameView.setText(preferences.getString(PREFS_DEVICE_NAME, ""));
fileNameView.setText(preferences.getString(PREFS_FILE_NAME, ""));
fileTypeView.setText(preferences.getString(PREFS_FILE_TYPE, ""));
fileScopeView.setText(preferences.getString(PREFS_FILE_SCOPE, ""));
fileSizeView.setText(preferences.getString(PREFS_FILE_SIZE, ""));
fileStatusView.setText(R.string.dfu_file_status_ok);
statusOk = true;
showProgressBar();
}
}
@@ -333,24 +335,24 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
@Override
protected void onResume() {
super.onResume();
mResumed = true;
if (mDfuCompleted)
resumed = true;
if (dfuCompleted)
onTransferCompleted();
if (mDfuError != null)
showErrorMessage(mDfuError);
if (mDfuCompleted || mDfuError != null) {
if (dfuError != null)
showErrorMessage(dfuError);
if (dfuCompleted || dfuError != null) {
// if this activity is still open and upload process was completed, cancel the notification
final NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
manager.cancel(DfuService.NOTIFICATION_ID);
mDfuCompleted = false;
mDfuError = null;
dfuCompleted = false;
dfuError = null;
}
}
@Override
protected void onPause() {
super.onPause();
mResumed = false;
resumed = false;
}
@Override
@@ -429,9 +431,9 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
switch (requestCode) {
case SELECT_FILE_REQ: {
// clear previous data
mFileType = mFileTypeTmp;
mFilePath = null;
mFileStreamUri = null;
fileType = fileTypeTmp;
filePath = null;
fileStreamUri = null;
// and read new one
final Uri uri = data.getData();
@@ -443,17 +445,17 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
// the direct path to the file has been returned
final String path = uri.getPath();
final File file = new File(path);
mFilePath = path;
filePath = path;
updateFileInfo(file.getName(), file.length(), mFileType);
updateFileInfo(file.getName(), file.length(), fileType);
} else if (uri.getScheme().equals("content")) {
// an Uri has been returned
mFileStreamUri = uri;
fileStreamUri = uri;
// if application returned Uri for streaming, let's us it. Does it works?
// FIXME both Uris works with Google Drive app. Why both? What's the difference? How about other apps like DropBox?
final Bundle extras = data.getExtras();
if (extras != null && extras.containsKey(Intent.EXTRA_STREAM))
mFileStreamUri = extras.getParcelable(Intent.EXTRA_STREAM);
fileStreamUri = extras.getParcelable(Intent.EXTRA_STREAM);
// file name and size must be obtained from Content Provider
final Bundle bundle = new Bundle();
@@ -463,8 +465,8 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
break;
}
case SELECT_INIT_FILE_REQ: {
mInitFilePath = null;
mInitFileStreamUri = null;
initFilePath = null;
initFileStreamUri = null;
// and read new one
final Uri uri = data.getData();
@@ -474,17 +476,17 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
*/
if (uri.getScheme().equals("file")) {
// the direct path to the file has been returned
mInitFilePath = uri.getPath();
mFileStatusView.setText(R.string.dfu_file_status_ok_with_init);
initFilePath = uri.getPath();
fileStatusView.setText(R.string.dfu_file_status_ok_with_init);
} else if (uri.getScheme().equals("content")) {
// an Uri has been returned
mInitFileStreamUri = uri;
initFileStreamUri = uri;
// if application returned Uri for streaming, let's us it. Does it works?
// FIXME both Uris works with Google Drive app. Why both? What's the difference? How about other apps like DropBox?
final Bundle extras = data.getExtras();
if (extras != null && extras.containsKey(Intent.EXTRA_STREAM))
mInitFileStreamUri = extras.getParcelable(Intent.EXTRA_STREAM);
mFileStatusView.setText(R.string.dfu_file_status_ok_with_init);
initFileStreamUri = extras.getParcelable(Intent.EXTRA_STREAM);
fileStatusView.setText(R.string.dfu_file_status_ok_with_init);
}
break;
}
@@ -506,12 +508,12 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
@Override
public void onLoaderReset(final Loader<Cursor> loader) {
mFileNameView.setText(null);
mFileTypeView.setText(null);
mFileSizeView.setText(null);
mFilePath = null;
mFileStreamUri = null;
mStatusOk = false;
fileNameView.setText(null);
fileTypeView.setText(null);
fileSizeView.setText(null);
filePath = null;
fileStreamUri = null;
statusOk = false;
}
@Override
@@ -527,17 +529,17 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
if (dataIndex != -1)
filePath = data.getString(dataIndex /* 2 DATA */);
if (!TextUtils.isEmpty(filePath))
mFilePath = filePath;
this.filePath = filePath;
updateFileInfo(fileName, fileSize, mFileType);
updateFileInfo(fileName, fileSize, fileType);
} else {
mFileNameView.setText(null);
mFileTypeView.setText(null);
mFileSizeView.setText(null);
mFilePath = null;
mFileStreamUri = null;
mFileStatusView.setText(R.string.dfu_file_status_error);
mStatusOk = false;
fileNameView.setText(null);
fileTypeView.setText(null);
fileSizeView.setText(null);
filePath = null;
fileStreamUri = null;
fileStatusView.setText(R.string.dfu_file_status_error);
statusOk = false;
}
}
@@ -548,37 +550,37 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
* @param fileSize file length
*/
private void updateFileInfo(final String fileName, final long fileSize, final int fileType) {
mFileNameView.setText(fileName);
fileNameView.setText(fileName);
switch (fileType) {
case DfuService.TYPE_AUTO:
mFileTypeView.setText(getResources().getStringArray(R.array.dfu_file_type)[0]);
fileTypeView.setText(getResources().getStringArray(R.array.dfu_file_type)[0]);
break;
case DfuService.TYPE_SOFT_DEVICE:
mFileTypeView.setText(getResources().getStringArray(R.array.dfu_file_type)[1]);
fileTypeView.setText(getResources().getStringArray(R.array.dfu_file_type)[1]);
break;
case DfuService.TYPE_BOOTLOADER:
mFileTypeView.setText(getResources().getStringArray(R.array.dfu_file_type)[2]);
fileTypeView.setText(getResources().getStringArray(R.array.dfu_file_type)[2]);
break;
case DfuService.TYPE_APPLICATION:
mFileTypeView.setText(getResources().getStringArray(R.array.dfu_file_type)[3]);
fileTypeView.setText(getResources().getStringArray(R.array.dfu_file_type)[3]);
break;
}
mFileSizeView.setText(getString(R.string.dfu_file_size_text, fileSize));
mFileScopeView.setText(getString(R.string.not_available));
final String extension = mFileType == DfuService.TYPE_AUTO ? "(?i)ZIP" : "(?i)HEX|BIN"; // (?i) = case insensitive
final boolean statusOk = mStatusOk = MimeTypeMap.getFileExtensionFromUrl(fileName).matches(extension);
mFileStatusView.setText(statusOk ? R.string.dfu_file_status_ok : R.string.dfu_file_status_invalid);
mUploadButton.setEnabled(mSelectedDevice != null && statusOk);
fileSizeView.setText(getString(R.string.dfu_file_size_text, fileSize));
fileScopeView.setText(getString(R.string.not_available));
final String extension = this.fileType == DfuService.TYPE_AUTO ? "(?i)ZIP" : "(?i)HEX|BIN"; // (?i) = case insensitive
final boolean statusOk = this.statusOk = MimeTypeMap.getFileExtensionFromUrl(fileName).matches(extension);
fileStatusView.setText(statusOk ? R.string.dfu_file_status_ok : R.string.dfu_file_status_invalid);
uploadButton.setEnabled(selectedDevice != null && statusOk);
// Ask the user for the Init packet file if HEX or BIN files are selected. In case of a ZIP file the Init packets should be included in the ZIP.
if (statusOk) {
if (fileType != DfuService.TYPE_AUTO) {
mScope = null;
mFileScopeView.setText(getString(R.string.not_available));
scope = null;
fileScopeView.setText(getString(R.string.not_available));
new AlertDialog.Builder(this).setTitle(R.string.dfu_file_init_title).setMessage(R.string.dfu_file_init_message)
.setNegativeButton(R.string.no, (dialog, which) -> {
mInitFilePath = null;
mInitFileStreamUri = null;
initFilePath = null;
initFileStreamUri = null;
}).setPositiveButton(R.string.yes, (dialog, which) -> {
final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType(DfuService.MIME_TYPE_OCTET_STREAM);
@@ -590,25 +592,25 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
.setSingleChoiceItems(R.array.dfu_file_scope, 0, (dialog, which) -> {
switch (which) {
case 0:
mScope = null;
scope = null;
break;
case 1:
mScope = DfuServiceInitiator.SCOPE_SYSTEM_COMPONENTS;
scope = DfuServiceInitiator.SCOPE_SYSTEM_COMPONENTS;
break;
case 2:
mScope = DfuServiceInitiator.SCOPE_APPLICATION;
scope = DfuServiceInitiator.SCOPE_APPLICATION;
break;
}
}).setPositiveButton(R.string.ok, (dialogInterface, i) -> {
int index;
if (mScope == null) {
if (scope == null) {
index = 0;
} else if (mScope == DfuServiceInitiator.SCOPE_SYSTEM_COMPONENTS) {
} else if (scope == DfuServiceInitiator.SCOPE_SYSTEM_COMPONENTS) {
index = 1;
} else {
index = 2;
}
mFileScopeView.setText(getResources().getStringArray(R.array.dfu_file_scope)[index]);
fileScopeView.setText(getResources().getStringArray(R.array.dfu_file_scope)[index]);
}).show();
}
}
@@ -630,9 +632,9 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
* @param view a button that was pressed
*/
public void onSelectFileClicked(final View view) {
mFileTypeTmp = mFileType;
fileTypeTmp = fileType;
int index = 0;
switch (mFileType) {
switch (fileType) {
case DfuService.TYPE_AUTO:
index = 0;
break;
@@ -651,16 +653,16 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
.setSingleChoiceItems(R.array.dfu_file_type, index, (dialog, which) -> {
switch (which) {
case 0:
mFileTypeTmp = DfuService.TYPE_AUTO;
fileTypeTmp = DfuService.TYPE_AUTO;
break;
case 1:
mFileTypeTmp = DfuService.TYPE_SOFT_DEVICE;
fileTypeTmp = DfuService.TYPE_SOFT_DEVICE;
break;
case 2:
mFileTypeTmp = DfuService.TYPE_BOOTLOADER;
fileTypeTmp = DfuService.TYPE_BOOTLOADER;
break;
case 3:
mFileTypeTmp = DfuService.TYPE_APPLICATION;
fileTypeTmp = DfuService.TYPE_APPLICATION;
break;
}
}).setPositiveButton(R.string.ok, (dialog, which) -> openFileChooser()).setNeutralButton(R.string.dfu_file_info, (dialog, which) -> {
@@ -671,7 +673,7 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
private void openFileChooser() {
final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType(mFileTypeTmp == DfuService.TYPE_AUTO ? DfuService.MIME_TYPE_ZIP : DfuService.MIME_TYPE_OCTET_STREAM);
intent.setType(fileTypeTmp == DfuService.TYPE_AUTO ? DfuService.MIME_TYPE_ZIP : DfuService.MIME_TYPE_OCTET_STREAM);
intent.addCategory(Intent.CATEGORY_OPENABLE);
if (intent.resolveActivity(getPackageManager()) != null) {
// file browser has been found on the device
@@ -705,7 +707,7 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
}
// Check whether the selected file is a HEX file (we are just checking the extension)
if (!mStatusOk) {
if (!statusOk) {
Toast.makeText(this, R.string.dfu_file_status_invalid_message, Toast.LENGTH_LONG).show();
return;
}
@@ -713,11 +715,11 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
// Save current state in order to restore it if user quit the Activity
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
final SharedPreferences.Editor editor = preferences.edit();
editor.putString(PREFS_DEVICE_NAME, mSelectedDevice.getName());
editor.putString(PREFS_FILE_NAME, mFileNameView.getText().toString());
editor.putString(PREFS_FILE_TYPE, mFileTypeView.getText().toString());
editor.putString(PREFS_FILE_SCOPE, mFileScopeView.getText().toString());
editor.putString(PREFS_FILE_SIZE, mFileSizeView.getText().toString());
editor.putString(PREFS_DEVICE_NAME, selectedDevice.getName());
editor.putString(PREFS_FILE_NAME, fileNameView.getText().toString());
editor.putString(PREFS_FILE_TYPE, fileTypeView.getText().toString());
editor.putString(PREFS_FILE_SCOPE, fileScopeView.getText().toString());
editor.putString(PREFS_FILE_SIZE, fileSizeView.getText().toString());
editor.apply();
showProgressBar();
@@ -733,19 +735,19 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
numberOfPackets = DfuServiceInitiator.DEFAULT_PRN_VALUE;
}
final DfuServiceInitiator starter = new DfuServiceInitiator(mSelectedDevice.getAddress())
.setDeviceName(mSelectedDevice.getName())
final DfuServiceInitiator starter = new DfuServiceInitiator(selectedDevice.getAddress())
.setDeviceName(selectedDevice.getName())
.setKeepBond(keepBond)
.setForceDfu(forceDfu)
.setPacketsReceiptNotificationsEnabled(enablePRNs)
.setPacketsReceiptNotificationsValue(numberOfPackets)
.setUnsafeExperimentalButtonlessServiceInSecureDfuEnabled(true);
if (mFileType == DfuService.TYPE_AUTO) {
starter.setZip(mFileStreamUri, mFilePath);
if (mScope != null)
starter.setScope(mScope);
if (fileType == DfuService.TYPE_AUTO) {
starter.setZip(fileStreamUri, filePath);
if (scope != null)
starter.setScope(scope);
} else {
starter.setBinOrHex(mFileType, mFileStreamUri, mFilePath).setInitFile(mInitFileStreamUri, mInitFilePath);
starter.setBinOrHex(fileType, fileStreamUri, filePath).setInitFile(initFileStreamUri, initFilePath);
}
starter.start(this, DfuService.class);
}
@@ -772,10 +774,10 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
}
@Override
public void onDeviceSelected(final BluetoothDevice device, final String name) {
mSelectedDevice = device;
mUploadButton.setEnabled(mStatusOk);
mDeviceNameView.setText(name != null ? name : getString(R.string.not_available));
public void onDeviceSelected(@NonNull final BluetoothDevice device, final String name) {
selectedDevice = device;
uploadButton.setEnabled(statusOk);
deviceNameView.setText(name != null ? name : getString(R.string.not_available));
}
@Override
@@ -784,15 +786,15 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
}
private void showProgressBar() {
mProgressBar.setVisibility(View.VISIBLE);
mTextPercentage.setVisibility(View.VISIBLE);
mTextPercentage.setText(null);
mTextUploading.setText(R.string.dfu_status_uploading);
mTextUploading.setVisibility(View.VISIBLE);
mConnectButton.setEnabled(false);
mSelectFileButton.setEnabled(false);
mUploadButton.setEnabled(true);
mUploadButton.setText(R.string.dfu_action_upload_cancel);
progressBar.setVisibility(View.VISIBLE);
textPercentage.setVisibility(View.VISIBLE);
textPercentage.setText(null);
textUploading.setText(R.string.dfu_status_uploading);
textUploading.setVisibility(View.VISIBLE);
connectButton.setEnabled(false);
selectFileButton.setEnabled(false);
uploadButton.setEnabled(true);
uploadButton.setText(R.string.dfu_action_upload_cancel);
}
private void onTransferCompleted() {
@@ -807,9 +809,9 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
@Override
public void onCancelUpload() {
mProgressBar.setIndeterminate(true);
mTextUploading.setText(R.string.dfu_status_aborting);
mTextPercentage.setText(null);
progressBar.setIndeterminate(true);
textUploading.setText(R.string.dfu_status_aborting);
textPercentage.setText(null);
}
private void showErrorMessage(final String message) {
@@ -818,28 +820,28 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
}
private void clearUI(final boolean clearDevice) {
mProgressBar.setVisibility(View.INVISIBLE);
mTextPercentage.setVisibility(View.INVISIBLE);
mTextUploading.setVisibility(View.INVISIBLE);
mConnectButton.setEnabled(true);
mSelectFileButton.setEnabled(true);
mUploadButton.setEnabled(false);
mUploadButton.setText(R.string.dfu_action_upload);
progressBar.setVisibility(View.INVISIBLE);
textPercentage.setVisibility(View.INVISIBLE);
textUploading.setVisibility(View.INVISIBLE);
connectButton.setEnabled(true);
selectFileButton.setEnabled(true);
uploadButton.setEnabled(false);
uploadButton.setText(R.string.dfu_action_upload);
if (clearDevice) {
mSelectedDevice = null;
mDeviceNameView.setText(R.string.dfu_default_name);
selectedDevice = null;
deviceNameView.setText(R.string.dfu_default_name);
}
// Application may have lost the right to these files if Activity was closed during upload (grant uri permission). Clear file related values.
mFileNameView.setText(null);
mFileTypeView.setText(null);
mFileScopeView.setText(null);
mFileSizeView.setText(null);
mFileStatusView.setText(R.string.dfu_file_status_no_file);
mFilePath = null;
mFileStreamUri = null;
mInitFilePath = null;
mInitFileStreamUri = null;
mStatusOk = false;
fileNameView.setText(null);
fileTypeView.setText(null);
fileScopeView.setText(null);
fileSizeView.setText(null);
fileStatusView.setText(R.string.dfu_file_status_no_file);
filePath = null;
fileStreamUri = null;
initFilePath = null;
initFileStreamUri = null;
statusOk = false;
}
private void showToast(final int messageResId) {

View File

@@ -25,6 +25,8 @@ package no.nordicsemi.android.nrftoolbox.dfu;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import no.nordicsemi.android.nrftoolbox.R;
@@ -52,7 +54,7 @@ public class DfuInitiatorActivity extends AppCompatActivity implements ScannerFr
}
@Override
public void onDeviceSelected(final BluetoothDevice device, final String name) {
public void onDeviceSelected(@NonNull final BluetoothDevice device, final String name) {
final Intent intent = getIntent();
final String overwrittenName = intent.getStringExtra(DfuService.EXTRA_DEVICE_NAME);
final String path = intent.getStringExtra(DfuService.EXTRA_FILE_PATH);

View File

@@ -39,7 +39,8 @@ public class NotificationActivity extends Activity {
final Intent parentIntent = new Intent(this, FeaturesActivity.class);
parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
final Intent startAppIntent = new Intent(this, DfuActivity.class);
startAppIntent.putExtras(getIntent().getExtras());
if (getIntent() != null && getIntent().getExtras() != null)
startAppIntent.putExtras(getIntent().getExtras());
startActivities(new Intent[] { parentIntent, startAppIntent });
}

View File

@@ -29,6 +29,8 @@ import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import no.nordicsemi.android.nrftoolbox.R;
/**
@@ -36,38 +38,38 @@ import no.nordicsemi.android.nrftoolbox.R;
* URLs are specified in res/values/strings_dfu.xml.
*/
public class FileBrowserAppsAdapter extends BaseAdapter {
private final LayoutInflater mInflater;
private final Resources mResources;
private final LayoutInflater inflater;
private final Resources resources;
public FileBrowserAppsAdapter(final Context context) {
mInflater = LayoutInflater.from(context);
mResources = context.getResources();
inflater = LayoutInflater.from(context);
resources = context.getResources();
}
@Override
public int getCount() {
return mResources.getStringArray(R.array.dfu_app_file_browser).length;
return resources.getStringArray(R.array.dfu_app_file_browser).length;
}
@Override
public Object getItem(int position) {
return mResources.getStringArray(R.array.dfu_app_file_browser_action)[position];
public Object getItem(final int position) {
return resources.getStringArray(R.array.dfu_app_file_browser_action)[position];
}
@Override
public long getItemId(int position) {
public long getItemId(final int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
public View getView(final int position, @Nullable final View convertView, @NonNull final ViewGroup parent) {
View view = convertView;
if (view == null) {
view = mInflater.inflate(R.layout.app_file_browser_item, parent, false);
view = inflater.inflate(R.layout.app_file_browser_item, parent, false);
}
final TextView item = (TextView) view;
item.setText(mResources.getStringArray(R.array.dfu_app_file_browser)[position]);
item.setText(resources.getStringArray(R.array.dfu_app_file_browser)[position]);
item.getCompoundDrawablesRelative()[0].setLevel(position);
return view;
}

View File

@@ -21,17 +21,17 @@
*/
package no.nordicsemi.android.nrftoolbox.dfu.fragment;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.DialogFragment;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import androidx.appcompat.app.AlertDialog;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import no.nordicsemi.android.nrftoolbox.R;
import no.nordicsemi.android.nrftoolbox.dfu.DfuService;
@@ -41,7 +41,7 @@ import no.nordicsemi.android.nrftoolbox.dfu.DfuService;
public class UploadCancelFragment extends DialogFragment {
private static final String TAG = "UploadCancelFragment";
private CancelFragmentListener mListener;
private CancelFragmentListener listener;
public interface CancelFragmentListener {
void onCancelUpload();
@@ -52,11 +52,11 @@ public class UploadCancelFragment extends DialogFragment {
}
@Override
public void onAttach(final Activity activity) {
super.onAttach(activity);
public void onAttach(@NonNull final Context context) {
super.onAttach(context);
try {
mListener = (CancelFragmentListener) activity;
listener = (CancelFragmentListener) context;
} catch (final ClassCastException e) {
Log.d(TAG, "The parent Activity must implement CancelFragmentListener interface");
}
@@ -65,20 +65,20 @@ public class UploadCancelFragment extends DialogFragment {
@NonNull
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
return new AlertDialog.Builder(getActivity()).setTitle(R.string.dfu_confirmation_dialog_title).setMessage(R.string.dfu_upload_dialog_cancel_message).setCancelable(false)
return new AlertDialog.Builder(requireContext()).setTitle(R.string.dfu_confirmation_dialog_title).setMessage(R.string.dfu_upload_dialog_cancel_message).setCancelable(false)
.setPositiveButton(R.string.yes, (dialog, whichButton) -> {
final LocalBroadcastManager manager = LocalBroadcastManager.getInstance(getActivity());
final LocalBroadcastManager manager = LocalBroadcastManager.getInstance(requireContext());
final Intent pauseAction = new Intent(DfuService.BROADCAST_ACTION);
pauseAction.putExtra(DfuService.EXTRA_ACTION, DfuService.ACTION_ABORT);
manager.sendBroadcast(pauseAction);
mListener.onCancelUpload();
listener.onCancelUpload();
}).setNegativeButton(R.string.no, (dialog, which) -> dialog.cancel()).create();
}
@Override
public void onCancel(final DialogInterface dialog) {
final LocalBroadcastManager manager = LocalBroadcastManager.getInstance(getActivity());
public void onCancel(@NonNull final DialogInterface dialog) {
final LocalBroadcastManager manager = LocalBroadcastManager.getInstance(requireContext());
final Intent pauseAction = new Intent(DfuService.BROADCAST_ACTION);
pauseAction.putExtra(DfuService.EXTRA_ACTION, DfuService.ACTION_RESUME);
manager.sendBroadcast(pauseAction);

View File

@@ -36,7 +36,12 @@ public class ZipInfoFragment extends DialogFragment {
@Override
@NonNull
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final View view = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_zip_info, null);
return new AlertDialog.Builder(getActivity()).setView(view).setTitle(R.string.dfu_file_info).setPositiveButton(R.string.ok, null).create();
final View view = LayoutInflater.from(requireContext())
.inflate(R.layout.fragment_zip_info, null);
return new AlertDialog.Builder(requireContext())
.setView(view)
.setTitle(R.string.dfu_file_info)
.setPositiveButton(R.string.ok, null)
.create();
}
}

View File

@@ -45,7 +45,7 @@ public class AboutDfuPreference extends Preference {
protected void onClick() {
final Context context = getContext();
final Intent intent = new Intent(Intent.ACTION_VIEW,
Uri.parse("https://www.nordicsemi.com/DocLib/Content/SDK_Doc/nRF5_SDK/v15-3-0/ble_sdk_app_dfu_bootloader"));
Uri.parse("https://infocenter.nordicsemi.com/topic/sdk_nrf5_v16.0.0/examples_bootloader.html?cp=7_1_4_4"));
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

View File

@@ -34,44 +34,44 @@ import android.widget.TextView;
import no.nordicsemi.android.nrftoolbox.R;
public class ExpandableRecordAdapter extends BaseExpandableListAdapter {;
private final GlucoseManager mGlucoseManager;
private final LayoutInflater mInflater;
private final Context mContext;
private SparseArray<GlucoseRecord> mRecords;
private final GlucoseManager glucoseManager;
private final LayoutInflater inflater;
private final Context context;
private SparseArray<GlucoseRecord> records;
public ExpandableRecordAdapter(final Context context, final GlucoseManager manager) {
mGlucoseManager = manager;
mContext = context;
mInflater = LayoutInflater.from(context);
mRecords = manager.getRecords().clone();
glucoseManager = manager;
this.context = context;
inflater = LayoutInflater.from(context);
records = manager.getRecords().clone();
}
@Override
public void notifyDataSetChanged() {
mRecords = mGlucoseManager.getRecords().clone();
records = glucoseManager.getRecords().clone();
super.notifyDataSetChanged();
}
@Override
public int getGroupCount() {
return mRecords.size();
return records.size();
}
@Override
public Object getGroup(final int groupPosition) {
return mRecords.valueAt(groupPosition);
return records.valueAt(groupPosition);
}
@Override
public long getGroupId(final int groupPosition) {
return mRecords.keyAt(groupPosition);
return records.keyAt(groupPosition);
}
@Override
public View getGroupView(final int position, boolean isExpanded, final View convertView, final ViewGroup parent) {
View view = convertView;
if (view == null) {
view = mInflater.inflate(R.layout.activity_feature_gls_item, parent, false);
view = inflater.inflate(R.layout.activity_feature_gls_item, parent, false);
final GroupViewHolder holder = new GroupViewHolder();
holder.time = view.findViewById(R.id.time);
@@ -83,16 +83,16 @@ public class ExpandableRecordAdapter extends BaseExpandableListAdapter {;
if (record == null)
return view; // this may happen during closing the activity
final GroupViewHolder holder = (GroupViewHolder) view.getTag();
holder.time.setText(mContext.getString(R.string.gls_timestamp, record.time));
holder.time.setText(context.getString(R.string.gls_timestamp, record.time));
try {
holder.details.setText(mContext.getResources().getStringArray(R.array.gls_type)[record.type]);
holder.details.setText(context.getResources().getStringArray(R.array.gls_type)[record.type]);
} catch (final ArrayIndexOutOfBoundsException e) {
holder.details.setText(mContext.getResources().getStringArray(R.array.gls_type)[0]);
holder.details.setText(context.getResources().getStringArray(R.array.gls_type)[0]);
}
if (record.unit == GlucoseRecord.UNIT_kgpl) {
holder.concentration.setText(mContext.getString(R.string.gls_value, record.glucoseConcentration * 100000.0f));
holder.concentration.setText(context.getString(R.string.gls_value, record.glucoseConcentration * 100000.0f));
} else {
holder.concentration.setText(mContext.getString(R.string.gls_value, record.glucoseConcentration * 1000.0f));
holder.concentration.setText(context.getString(R.string.gls_value, record.glucoseConcentration * 1000.0f));
}
return view;
}
@@ -123,7 +123,7 @@ public class ExpandableRecordAdapter extends BaseExpandableListAdapter {;
@Override
public Object getChild(final int groupPosition, final int childPosition) {
final Resources resources = mContext.getResources();
final Resources resources = context.getResources();
final GlucoseRecord record = (GlucoseRecord) getGroup(groupPosition);
String tmp;
switch (childIdToItemId(childPosition, record)) {
@@ -226,7 +226,7 @@ public class ExpandableRecordAdapter extends BaseExpandableListAdapter {;
public View getChildView(final int groupPosition, final int childPosition, final boolean isLastChild, final View convertView, final ViewGroup parent) {
View view = convertView;
if (view == null) {
view = mInflater.inflate(R.layout.activity_feature_gls_subitem, parent, false);
view = inflater.inflate(R.layout.activity_feature_gls_subitem, parent, false);
final ChildViewHolder holder = new ChildViewHolder();
holder.title = view.findViewById(android.R.id.text1);
holder.details = view.findViewById(android.R.id.text2);

View File

@@ -43,13 +43,13 @@ public class GlucoseActivity extends BleProfileExpandableListActivity implements
@SuppressWarnings("unused")
private static final String TAG = "GlucoseActivity";
private BaseExpandableListAdapter mAdapter;
private GlucoseManager mGlucoseManager;
private BaseExpandableListAdapter adapter;
private GlucoseManager glucoseManager;
private View mControlPanelStd;
private View mControlPanelAbort;
private TextView mUnitView;
private TextView mBatteryLevelView;
private View controlPanelStd;
private View controlPanelAbort;
private TextView unitView;
private TextView batteryLevelView;
@Override
protected void onCreateView(final Bundle savedInstanceState) {
@@ -58,14 +58,14 @@ public class GlucoseActivity extends BleProfileExpandableListActivity implements
}
private void setGUI() {
mUnitView = findViewById(R.id.unit);
mControlPanelStd = findViewById(R.id.gls_control_std);
mControlPanelAbort = findViewById(R.id.gls_control_abort);
mBatteryLevelView = findViewById(R.id.battery);
unitView = findViewById(R.id.unit);
controlPanelStd = findViewById(R.id.gls_control_std);
controlPanelAbort = findViewById(R.id.gls_control_abort);
batteryLevelView = findViewById(R.id.battery);
findViewById(R.id.action_last).setOnClickListener(v -> mGlucoseManager.getLastRecord());
findViewById(R.id.action_all).setOnClickListener(v -> mGlucoseManager.getAllRecords());
findViewById(R.id.action_abort).setOnClickListener(v -> mGlucoseManager.abort());
findViewById(R.id.action_last).setOnClickListener(v -> glucoseManager.getLastRecord());
findViewById(R.id.action_all).setOnClickListener(v -> glucoseManager.getAllRecords());
findViewById(R.id.action_abort).setOnClickListener(v -> glucoseManager.abort());
// create popup menu attached to the button More
findViewById(R.id.action_more).setOnClickListener(v -> {
@@ -76,12 +76,12 @@ public class GlucoseActivity extends BleProfileExpandableListActivity implements
menu.show();
});
setListAdapter(mAdapter = new ExpandableRecordAdapter(this, mGlucoseManager));
setListAdapter(adapter = new ExpandableRecordAdapter(this, glucoseManager));
}
@Override
protected LoggableBleManager<GlucoseManagerCallbacks> initializeManager() {
GlucoseManager manager = mGlucoseManager = GlucoseManager.getGlucoseManager(getApplicationContext());
GlucoseManager manager = glucoseManager = GlucoseManager.getGlucoseManager(getApplicationContext());
manager.setGattCallbacks(this);
return manager;
}
@@ -90,16 +90,16 @@ public class GlucoseActivity extends BleProfileExpandableListActivity implements
public boolean onMenuItemClick(final MenuItem item) {
switch (item.getItemId()) {
case R.id.action_refresh:
mGlucoseManager.refreshRecords();
glucoseManager.refreshRecords();
break;
case R.id.action_first:
mGlucoseManager.getFirstRecord();
glucoseManager.getFirstRecord();
break;
case R.id.action_clear:
mGlucoseManager.clear();
glucoseManager.clear();
break;
case R.id.action_delete_all:
mGlucoseManager.deleteAllRecords();
glucoseManager.deleteAllRecords();
break;
}
return true;
@@ -127,14 +127,14 @@ public class GlucoseActivity extends BleProfileExpandableListActivity implements
@Override
protected void setDefaultUI() {
mGlucoseManager.clear();
mBatteryLevelView.setText(R.string.not_available);
glucoseManager.clear();
batteryLevelView.setText(R.string.not_available);
}
private void setOperationInProgress(final boolean progress) {
runOnUiThread(() -> {
mControlPanelStd.setVisibility(!progress ? View.VISIBLE : View.GONE);
mControlPanelAbort.setVisibility(progress ? View.VISIBLE : View.GONE);
controlPanelStd.setVisibility(!progress ? View.VISIBLE : View.GONE);
controlPanelAbort.setVisibility(progress ? View.VISIBLE : View.GONE);
});
}
@@ -142,55 +142,55 @@ public class GlucoseActivity extends BleProfileExpandableListActivity implements
public void onDeviceDisconnected(@NonNull final BluetoothDevice device) {
super.onDeviceDisconnected(device);
setOperationInProgress(false);
runOnUiThread(() -> mBatteryLevelView.setText(R.string.not_available));
runOnUiThread(() -> batteryLevelView.setText(R.string.not_available));
}
@Override
public void onOperationStarted(final BluetoothDevice device) {
public void onOperationStarted(@NonNull final BluetoothDevice device) {
setOperationInProgress(true);
}
@Override
public void onOperationCompleted(final BluetoothDevice device) {
public void onOperationCompleted(@NonNull final BluetoothDevice device) {
setOperationInProgress(false);
runOnUiThread(() -> {
final SparseArray<GlucoseRecord> records = mGlucoseManager.getRecords();
final SparseArray<GlucoseRecord> records = glucoseManager.getRecords();
if (records.size() > 0) {
final int unit = records.valueAt(0).unit;
mUnitView.setVisibility(View.VISIBLE);
mUnitView.setText(unit == GlucoseRecord.UNIT_kgpl ? R.string.gls_unit_mgpdl : R.string.gls_unit_mmolpl);
unitView.setVisibility(View.VISIBLE);
unitView.setText(unit == GlucoseRecord.UNIT_kgpl ? R.string.gls_unit_mgpdl : R.string.gls_unit_mmolpl);
} else {
mUnitView.setVisibility(View.GONE);
unitView.setVisibility(View.GONE);
}
mAdapter.notifyDataSetChanged();
adapter.notifyDataSetChanged();
});
}
@Override
public void onOperationAborted(final BluetoothDevice device) {
public void onOperationAborted(@NonNull final BluetoothDevice device) {
setOperationInProgress(false);
}
@Override
public void onOperationNotSupported(final BluetoothDevice device) {
public void onOperationNotSupported(@NonNull final BluetoothDevice device) {
setOperationInProgress(false);
showToast(R.string.gls_operation_not_supported);
}
@Override
public void onOperationFailed(final BluetoothDevice device) {
public void onOperationFailed(@NonNull final BluetoothDevice device) {
setOperationInProgress(false);
showToast(R.string.gls_operation_failed);
}
@Override
public void onDatasetChanged(final BluetoothDevice device) {
public void onDataSetChanged(@NonNull final BluetoothDevice device) {
// Do nothing. Refreshing the list is done in onOperationCompleted
}
@Override
public void onNumberOfRecordsRequested(final BluetoothDevice device, final int value) {
public void onNumberOfRecordsRequested(@NonNull final BluetoothDevice device, final int value) {
if (value == 0)
showToast(R.string.gls_progress_zero);
else
@@ -199,6 +199,6 @@ public class GlucoseActivity extends BleProfileExpandableListActivity implements
@Override
public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) {
runOnUiThread(() -> mBatteryLevelView.setText(getString(R.string.battery, batteryLevel)));
runOnUiThread(() -> batteryLevelView.setText(getString(R.string.battery, batteryLevel)));
}
}

View File

@@ -21,6 +21,7 @@
*/
package no.nordicsemi.android.nrftoolbox.gls;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
@@ -52,7 +53,7 @@ public class GlucoseManager extends BatteryManager<GlucoseManagerCallbacks> {
private static final String TAG = "GlucoseManager";
/** Glucose service UUID */
public final static UUID GLS_SERVICE_UUID = UUID.fromString("00001808-0000-1000-8000-00805f9b34fb");
final static UUID GLS_SERVICE_UUID = UUID.fromString("00001808-0000-1000-8000-00805f9b34fb");
/** Glucose Measurement characteristic UUID */
private final static UUID GM_CHARACTERISTIC = UUID.fromString("00002A18-0000-1000-8000-00805f9b34fb");
/** Glucose Measurement Context characteristic UUID */
@@ -62,39 +63,39 @@ public class GlucoseManager extends BatteryManager<GlucoseManagerCallbacks> {
/** Record Access Control Point characteristic UUID */
private final static UUID RACP_CHARACTERISTIC = UUID.fromString("00002A52-0000-1000-8000-00805f9b34fb");
private BluetoothGattCharacteristic mGlucoseMeasurementCharacteristic;
private BluetoothGattCharacteristic mGlucoseMeasurementContextCharacteristic;
private BluetoothGattCharacteristic mRecordAccessControlPointCharacteristic;
private BluetoothGattCharacteristic glucoseMeasurementCharacteristic;
private BluetoothGattCharacteristic glucoseMeasurementContextCharacteristic;
private BluetoothGattCharacteristic recordAccessControlPointCharacteristic;
private final SparseArray<GlucoseRecord> mRecords = new SparseArray<>();
private Handler mHandler;
private static GlucoseManager mInstance;
private final SparseArray<GlucoseRecord> records = new SparseArray<>();
private Handler handler;
private static GlucoseManager instance;
/**
* Returns the singleton implementation of GlucoseManager.
*/
public static GlucoseManager getGlucoseManager(final Context context) {
if (mInstance == null)
mInstance = new GlucoseManager(context);
return mInstance;
static GlucoseManager getGlucoseManager(@NonNull final Context context) {
if (instance == null)
instance = new GlucoseManager(context);
return instance;
}
private GlucoseManager(final Context context) {
super(context);
mHandler = new Handler();
handler = new Handler();
}
@NonNull
@Override
protected BatteryManagerGattCallback getGattCallback() {
return mGattCallback;
return gattCallback;
}
/**
* BluetoothGatt callbacks for connection/disconnection, service discovery,
* receiving notification, etc.
*/
private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() {
private final BatteryManagerGattCallback gattCallback = new BatteryManagerGattCallback() {
@Override
protected void initialize() {
@@ -111,13 +112,13 @@ public class GlucoseManager extends BatteryManager<GlucoseManagerCallbacks> {
// However... the original approach works for the Battery Level CCCD, which makes it
// even weirder.
/*
gatt.setCharacteristicNotification(mGlucoseMeasurementCharacteristic, true);
if (mGlucoseMeasurementContextCharacteristic != null) {
device.setCharacteristicNotification(mGlucoseMeasurementContextCharacteristic, true);
gatt.setCharacteristicNotification(glucoseMeasurementCharacteristic, true);
if (glucoseMeasurementContextCharacteristic != null) {
device.setCharacteristicNotification(glucoseMeasurementContextCharacteristic, true);
}
device.setCharacteristicNotification(mRecordAccessControlPointCharacteristic, true);
device.setCharacteristicNotification(recordAccessControlPointCharacteristic, true);
*/
setNotificationCallback(mGlucoseMeasurementCharacteristic)
setNotificationCallback(glucoseMeasurementContextCharacteristic)
.with(new GlucoseMeasurementDataCallback() {
@Override
public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
@@ -141,17 +142,17 @@ public class GlucoseManager extends BatteryManager<GlucoseManagerCallbacks> {
record.status = status != null ? status.value : 0;
// insert the new record to storage
mRecords.put(record.sequenceNumber, record);
mHandler.post(() -> {
records.put(record.sequenceNumber, record);
handler.post(() -> {
// if there is no context information following the measurement data,
// notify callback about the new record
if (!contextInformationFollows)
mCallbacks.onDatasetChanged(device);
callbacks.onDataSetChanged(device);
});
}
});
setNotificationCallback(mGlucoseMeasurementContextCharacteristic)
setNotificationCallback(glucoseMeasurementContextCharacteristic)
.with(new GlucoseMeasurementContextDataCallback() {
@Override
public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
@@ -167,7 +168,7 @@ public class GlucoseManager extends BatteryManager<GlucoseManagerCallbacks> {
@Nullable final Integer exerciseIntensity, @Nullable final Medication medication,
@Nullable final Float medicationAmount, @Nullable final Integer medicationUnit,
@Nullable final Float HbA1c) {
final GlucoseRecord record = mRecords.get(sequenceNumber);
final GlucoseRecord record = records.get(sequenceNumber);
if (record == null) {
DebugLogger.w(TAG, "Context information with unknown sequence number: " + sequenceNumber);
return;
@@ -186,14 +187,14 @@ public class GlucoseManager extends BatteryManager<GlucoseManagerCallbacks> {
context.medicationUnit = medicationUnit != null ? medicationUnit : UNIT_mg;
context.HbA1c = HbA1c != null ? HbA1c : 0;
mHandler.post(() -> {
handler.post(() -> {
// notify callback about the new record
mCallbacks.onDatasetChanged(device);
callbacks.onDataSetChanged(device);
});
}
});
setIndicationCallback(mRecordAccessControlPointCharacteristic)
setIndicationCallback(recordAccessControlPointCharacteristic)
.with(new RecordAccessControlPointDataCallback() {
@Override
public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
@@ -201,57 +202,62 @@ public class GlucoseManager extends BatteryManager<GlucoseManagerCallbacks> {
super.onDataReceived(device, data);
}
@SuppressLint("SwitchIntDef")
@Override
public void onRecordAccessOperationCompleted(@NonNull final BluetoothDevice device, final int requestCode) {
public void onRecordAccessOperationCompleted(@NonNull final BluetoothDevice device,
@RACPOpCode final int requestCode) {
//noinspection SwitchStatementWithTooFewBranches
switch (requestCode) {
case RACP_OP_CODE_ABORT_OPERATION:
mCallbacks.onOperationAborted(device);
callbacks.onOperationAborted(device);
break;
default:
mCallbacks.onOperationCompleted(device);
callbacks.onOperationCompleted(device);
break;
}
}
@Override
public void onRecordAccessOperationCompletedWithNoRecordsFound(@NonNull final BluetoothDevice device, final int requestCode) {
mCallbacks.onOperationCompleted(device);
public void onRecordAccessOperationCompletedWithNoRecordsFound(@NonNull final BluetoothDevice device,
@RACPOpCode final int requestCode) {
callbacks.onOperationCompleted(device);
}
@Override
public void onNumberOfRecordsReceived(@NonNull final BluetoothDevice device, final int numberOfRecords) {
mCallbacks.onNumberOfRecordsRequested(device, numberOfRecords);
callbacks.onNumberOfRecordsRequested(device, numberOfRecords);
if (numberOfRecords > 0) {
if (mRecords.size() > 0) {
final int sequenceNumber = mRecords.keyAt(mRecords.size() - 1) + 1;
writeCharacteristic(mRecordAccessControlPointCharacteristic,
if (records.size() > 0) {
final int sequenceNumber = records.keyAt(records.size() - 1) + 1;
writeCharacteristic(recordAccessControlPointCharacteristic,
RecordAccessControlPointData.reportStoredRecordsGreaterThenOrEqualTo(sequenceNumber))
.enqueue();
} else {
writeCharacteristic(mRecordAccessControlPointCharacteristic,
writeCharacteristic(recordAccessControlPointCharacteristic,
RecordAccessControlPointData.reportAllStoredRecords())
.enqueue();
}
} else {
mCallbacks.onOperationCompleted(device);
callbacks.onOperationCompleted(device);
}
}
@Override
public void onRecordAccessOperationError(@NonNull final BluetoothDevice device,
final int requestCode, final int errorCode) {
@RACPOpCode final int requestCode,
@RACPErrorCode final int errorCode) {
log(Log.WARN, "Record Access operation failed (error " + errorCode + ")");
if (errorCode == RACP_ERROR_OP_CODE_NOT_SUPPORTED) {
mCallbacks.onOperationNotSupported(device);
callbacks.onOperationNotSupported(device);
} else {
mCallbacks.onOperationFailed(device);
callbacks.onOperationFailed(device);
}
}
});
enableNotifications(mGlucoseMeasurementCharacteristic).enqueue();
enableNotifications(mGlucoseMeasurementContextCharacteristic).enqueue();
enableIndications(mRecordAccessControlPointCharacteristic)
enableNotifications(glucoseMeasurementContextCharacteristic).enqueue();
enableNotifications(glucoseMeasurementContextCharacteristic).enqueue();
enableIndications(recordAccessControlPointCharacteristic)
.fail((device, status) -> log(Log.WARN, "Failed to enabled Record Access Control Point indications (error " + status + ")"))
.enqueue();
}
@@ -260,24 +266,24 @@ public class GlucoseManager extends BatteryManager<GlucoseManagerCallbacks> {
public boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) {
final BluetoothGattService service = gatt.getService(GLS_SERVICE_UUID);
if (service != null) {
mGlucoseMeasurementCharacteristic = service.getCharacteristic(GM_CHARACTERISTIC);
mGlucoseMeasurementContextCharacteristic = service.getCharacteristic(GM_CONTEXT_CHARACTERISTIC);
mRecordAccessControlPointCharacteristic = service.getCharacteristic(RACP_CHARACTERISTIC);
glucoseMeasurementCharacteristic = service.getCharacteristic(GM_CHARACTERISTIC);
glucoseMeasurementContextCharacteristic = service.getCharacteristic(GM_CONTEXT_CHARACTERISTIC);
recordAccessControlPointCharacteristic = service.getCharacteristic(RACP_CHARACTERISTIC);
}
return mGlucoseMeasurementCharacteristic != null && mRecordAccessControlPointCharacteristic != null;
return glucoseMeasurementCharacteristic != null && recordAccessControlPointCharacteristic != null;
}
@Override
protected boolean isOptionalServiceSupported(@NonNull BluetoothGatt gatt) {
super.isOptionalServiceSupported(gatt);
return mGlucoseMeasurementContextCharacteristic != null;
return glucoseMeasurementContextCharacteristic != null;
}
@Override
protected void onDeviceDisconnected() {
mGlucoseMeasurementCharacteristic = null;
mGlucoseMeasurementContextCharacteristic = null;
mRecordAccessControlPointCharacteristic = null;
glucoseMeasurementCharacteristic = null;
glucoseMeasurementContextCharacteristic = null;
recordAccessControlPointCharacteristic = null;
}
};
@@ -286,16 +292,16 @@ public class GlucoseManager extends BatteryManager<GlucoseManagerCallbacks> {
*
* @return the records list.
*/
public SparseArray<GlucoseRecord> getRecords() {
return mRecords;
SparseArray<GlucoseRecord> getRecords() {
return records;
}
/**
* Clears the records list locally.
*/
public void clear() {
mRecords.clear();
mCallbacks.onOperationCompleted(getBluetoothDevice());
records.clear();
callbacks.onOperationCompleted(getBluetoothDevice());
}
/**
@@ -303,13 +309,13 @@ public class GlucoseManager extends BatteryManager<GlucoseManagerCallbacks> {
* be returned to Glucose Measurement characteristic as a notification followed by Record Access
* Control Point indication with status code Success or other in case of error.
*/
public void getLastRecord() {
if (mRecordAccessControlPointCharacteristic == null)
void getLastRecord() {
if (recordAccessControlPointCharacteristic == null)
return;
clear();
mCallbacks.onOperationStarted(getBluetoothDevice());
writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.reportLastStoredRecord())
callbacks.onOperationStarted(getBluetoothDevice());
writeCharacteristic(recordAccessControlPointCharacteristic, RecordAccessControlPointData.reportLastStoredRecord())
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
.enqueue();
}
@@ -319,13 +325,13 @@ public class GlucoseManager extends BatteryManager<GlucoseManagerCallbacks> {
* returned to Glucose Measurement characteristic as a notification followed by Record Access
* Control Point indication with status code Success or other in case of error.
*/
public void getFirstRecord() {
if (mRecordAccessControlPointCharacteristic == null)
void getFirstRecord() {
if (recordAccessControlPointCharacteristic == null)
return;
clear();
mCallbacks.onOperationStarted(getBluetoothDevice());
writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.reportFirstStoredRecord())
callbacks.onOperationStarted(getBluetoothDevice());
writeCharacteristic(recordAccessControlPointCharacteristic, RecordAccessControlPointData.reportFirstStoredRecord())
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
.enqueue();
}
@@ -336,13 +342,13 @@ public class GlucoseManager extends BatteryManager<GlucoseManagerCallbacks> {
* will be returned to Glucose Measurement characteristic as a notification followed by
* Record Access Control Point indication with status code Success or other in case of error.
*/
public void getAllRecords() {
if (mRecordAccessControlPointCharacteristic == null)
void getAllRecords() {
if (recordAccessControlPointCharacteristic == null)
return;
clear();
mCallbacks.onOperationStarted(getBluetoothDevice());
writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.reportNumberOfAllStoredRecords())
callbacks.onOperationStarted(getBluetoothDevice());
writeCharacteristic(recordAccessControlPointCharacteristic, RecordAccessControlPointData.reportNumberOfAllStoredRecords())
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
.enqueue();
}
@@ -357,19 +363,19 @@ public class GlucoseManager extends BatteryManager<GlucoseManagerCallbacks> {
* E.g. if you have pressed Last and then Refresh, than it will try to get only newer records.
* However if there are no records, it will download all existing (using {@link #getAllRecords()}).
*/
public void refreshRecords() {
if (mRecordAccessControlPointCharacteristic == null)
void refreshRecords() {
if (recordAccessControlPointCharacteristic == null)
return;
if (mRecords.size() == 0) {
if (records.size() == 0) {
getAllRecords();
} else {
mCallbacks.onOperationStarted(getBluetoothDevice());
callbacks.onOperationStarted(getBluetoothDevice());
// obtain the last sequence number
final int sequenceNumber = mRecords.keyAt(mRecords.size() - 1) + 1;
final int sequenceNumber = records.keyAt(records.size() - 1) + 1;
writeCharacteristic(mRecordAccessControlPointCharacteristic,
writeCharacteristic(recordAccessControlPointCharacteristic,
RecordAccessControlPointData.reportStoredRecordsGreaterThenOrEqualTo(sequenceNumber))
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
.enqueue();
@@ -381,11 +387,11 @@ public class GlucoseManager extends BatteryManager<GlucoseManagerCallbacks> {
/**
* Sends abort operation signal to the device.
*/
public void abort() {
if (mRecordAccessControlPointCharacteristic == null)
void abort() {
if (recordAccessControlPointCharacteristic == null)
return;
writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.abortOperation())
writeCharacteristic(recordAccessControlPointCharacteristic, RecordAccessControlPointData.abortOperation())
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
.enqueue();
}
@@ -394,13 +400,13 @@ public class GlucoseManager extends BatteryManager<GlucoseManagerCallbacks> {
* Sends the request to delete all data from the device. A Record Access Control Point
* indication with status code Success (or other in case of error) will be send.
*/
public void deleteAllRecords() {
if (mRecordAccessControlPointCharacteristic == null)
void deleteAllRecords() {
if (recordAccessControlPointCharacteristic == null)
return;
clear();
mCallbacks.onOperationStarted(getBluetoothDevice());
writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.deleteAllStoredRecords())
callbacks.onOperationStarted(getBluetoothDevice());
writeCharacteristic(recordAccessControlPointCharacteristic, RecordAccessControlPointData.deleteAllStoredRecords())
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
.enqueue();
}

View File

@@ -23,22 +23,23 @@ package no.nordicsemi.android.nrftoolbox.gls;
import android.bluetooth.BluetoothDevice;
import androidx.annotation.NonNull;
import no.nordicsemi.android.ble.BleManagerCallbacks;
import no.nordicsemi.android.nrftoolbox.battery.BatteryManagerCallbacks;
public interface GlucoseManagerCallbacks extends BatteryManagerCallbacks {
void onOperationStarted(final BluetoothDevice device);
void onOperationStarted(@NonNull final BluetoothDevice device);
void onOperationCompleted(final BluetoothDevice device);
void onOperationCompleted(@NonNull final BluetoothDevice device);
void onOperationFailed(final BluetoothDevice device);
void onOperationFailed(@NonNull final BluetoothDevice device);
void onOperationAborted(final BluetoothDevice device);
void onOperationAborted(@NonNull final BluetoothDevice device);
void onOperationNotSupported(final BluetoothDevice device);
void onOperationNotSupported(@NonNull final BluetoothDevice device);
void onDatasetChanged(final BluetoothDevice device);
void onDataSetChanged(@NonNull final BluetoothDevice device);
void onNumberOfRecordsRequested(final BluetoothDevice device, final int value);
void onNumberOfRecordsRequested(@NonNull final BluetoothDevice device, final int value);
}

View File

@@ -23,32 +23,34 @@ package no.nordicsemi.android.nrftoolbox.gls;
import java.util.Calendar;
@SuppressWarnings("unused")
public class GlucoseRecord {
public static final int UNIT_kgpl = 0;
public static final int UNIT_molpl = 1;
static final int UNIT_kgpl = 0;
private static final int UNIT_molpl = 1;
/** Record sequence number */
protected int sequenceNumber;
int sequenceNumber;
/** The base time of the measurement */
protected Calendar time;
Calendar time;
/** Time offset of the record */
protected int timeOffset;
int timeOffset;
/** The glucose concentration. 0 if not present */
protected float glucoseConcentration;
float glucoseConcentration;
/** Concentration unit. One of the following: {@link GlucoseRecord#UNIT_kgpl}, {@link GlucoseRecord#UNIT_molpl} */
protected int unit;
int unit;
/** The type of the record. 0 if not present */
protected int type;
int type;
/** The sample location. 0 if unknown */
protected int sampleLocation;
int sampleLocation;
/** Sensor status annunciation flags. 0 if not present */
protected int status;
int status;
protected MeasurementContext context;
public static class MeasurementContext {
public static final int UNIT_kg = 0;
public static final int UNIT_l = 1;
@SuppressWarnings("unused")
static class MeasurementContext {
static final int UNIT_kg = 0;
static final int UNIT_l = 1;
/**
* One of the following:<br/>
@@ -61,9 +63,9 @@ public class GlucoseRecord {
* 6 Supper<br/>
* 7 Brunch
*/
protected int carbohydrateId;
int carbohydrateId;
/** Number of kilograms of carbohydrate */
protected float carbohydrateUnits;
float carbohydrateUnits;
/**
* One of the following:<br/>
* 0 Not present<br/>
@@ -73,7 +75,7 @@ public class GlucoseRecord {
* 4 Casual (snacks, drinks, etc.)<br/>
* 5 Bedtime
*/
protected int meal;
int meal;
/**
* One of the following:<br/>
* 0 Not present<br/>
@@ -82,7 +84,7 @@ public class GlucoseRecord {
* 3 Lab test<br/>
* 15 Tester value not available
*/
protected int tester;
int tester;
/**
* One of the following:<br/>
* 0 Not present<br/>
@@ -93,11 +95,11 @@ public class GlucoseRecord {
* 5 No health issues<br/>
* 15 Tester value not available
*/
protected int health;
int health;
/** Exercise duration in seconds. 0 if not present */
protected int exerciseDuration;
int exerciseDuration;
/** Exercise intensity in percent. 0 if not present */
protected int exerciseIntensity;
int exerciseIntensity;
/**
* One of the following:<br/>
* 0 Not present<br/>
@@ -107,12 +109,12 @@ public class GlucoseRecord {
* 4 Long acting insulin<br/>
* 5 Pre-mixed insulin
*/
protected int medicationId;
int medicationId;
/** Quantity of medication. See {@link #medicationUnit} for the unit. */
protected float medicationQuantity;
float medicationQuantity;
/** One of the following: {@link GlucoseRecord.MeasurementContext#UNIT_kg}, {@link GlucoseRecord.MeasurementContext#UNIT_l}. */
protected int medicationUnit;
int medicationUnit;
/** HbA1c value. 0 if not present */
protected float HbA1c;
float HbA1c;
}
}

View File

@@ -27,6 +27,8 @@ import android.content.Intent;
import android.graphics.Point;
import android.os.Bundle;
import android.os.Handler;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.view.ViewGroup;
@@ -57,17 +59,17 @@ public class HRSActivity extends BleProfileActivity implements HRSManagerCallbac
private final static int REFRESH_INTERVAL = 1000; // 1 second interval
private Handler mHandler = new Handler();
private Handler handler = new Handler();
private boolean isGraphInProgress = false;
private GraphicalView mGraphView;
private LineGraphView mLineGraph;
private TextView mHRSValue, mHRSPosition;
private TextView mBatteryLevelView;
private GraphicalView graphView;
private LineGraphView lineGraph;
private TextView hrValueView, hrLocationView;
private TextView batteryLevelView;
private int mHrmValue = 0;
private int mCounter = 0;
private int hrValue = 0;
private int counter = 0;
@Override
protected void onCreateView(final Bundle savedInstanceState) {
@@ -76,17 +78,17 @@ public class HRSActivity extends BleProfileActivity implements HRSManagerCallbac
}
private void setGUI() {
mLineGraph = LineGraphView.getLineGraphView();
mHRSValue = findViewById(R.id.text_hrs_value);
mHRSPosition = findViewById(R.id.text_hrs_position);
mBatteryLevelView = findViewById(R.id.battery);
lineGraph = LineGraphView.getLineGraphView();
hrValueView = findViewById(R.id.text_hrs_value);
hrLocationView = findViewById(R.id.text_hrs_position);
batteryLevelView = findViewById(R.id.battery);
showGraph();
}
private void showGraph() {
mGraphView = mLineGraph.getView(this);
graphView = lineGraph.getView(this);
ViewGroup layout = findViewById(R.id.graph_hrs);
layout.addView(mGraphView);
layout.addView(graphView);
}
@Override
@@ -109,20 +111,20 @@ public class HRSActivity extends BleProfileActivity implements HRSManagerCallbac
super.onRestoreInstanceState(savedInstanceState);
isGraphInProgress = savedInstanceState.getBoolean(GRAPH_STATUS);
mCounter = savedInstanceState.getInt(GRAPH_COUNTER);
mHrmValue = savedInstanceState.getInt(HR_VALUE);
counter = savedInstanceState.getInt(GRAPH_COUNTER);
hrValue = savedInstanceState.getInt(HR_VALUE);
if (isGraphInProgress)
startShowGraph();
}
@Override
protected void onSaveInstanceState(final Bundle outState) {
protected void onSaveInstanceState(@NonNull final Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(GRAPH_STATUS, isGraphInProgress);
outState.putInt(GRAPH_COUNTER, mCounter);
outState.putInt(HR_VALUE, mHrmValue);
outState.putInt(GRAPH_COUNTER, counter);
outState.putInt(HR_VALUE, hrValue);
}
@Override
@@ -153,35 +155,35 @@ public class HRSActivity extends BleProfileActivity implements HRSManagerCallbac
}
private void updateGraph(final int hrmValue) {
mCounter++;
mLineGraph.addValue(new Point(mCounter, hrmValue));
mGraphView.repaint();
counter++;
lineGraph.addValue(new Point(counter, hrmValue));
graphView.repaint();
}
private Runnable mRepeatTask = new Runnable() {
private Runnable repeatTask = new Runnable() {
@Override
public void run() {
if (mHrmValue > 0)
updateGraph(mHrmValue);
if (hrValue > 0)
updateGraph(hrValue);
if (isGraphInProgress)
mHandler.postDelayed(mRepeatTask, REFRESH_INTERVAL);
handler.postDelayed(repeatTask, REFRESH_INTERVAL);
}
};
void startShowGraph() {
isGraphInProgress = true;
mRepeatTask.run();
repeatTask.run();
}
void stopShowGraph() {
isGraphInProgress = false;
mHandler.removeCallbacks(mRepeatTask);
handler.removeCallbacks(repeatTask);
}
@Override
protected LoggableBleManager<HRSManagerCallbacks> initializeManager() {
final HRSManager manager = HRSManager.getInstance(getApplicationContext());
manager.setGattCallbacks(this);
manager.setManagerCallbacks(this);
return manager;
}
@@ -197,52 +199,53 @@ public class HRSActivity extends BleProfileActivity implements HRSManagerCallbac
@Override
public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) {
runOnUiThread(() -> mBatteryLevelView.setText(getString(R.string.battery, batteryLevel)));
runOnUiThread(() -> this.batteryLevelView.setText(getString(R.string.battery, batteryLevel)));
}
@Override
public void onBodySensorLocationReceived(@NonNull final BluetoothDevice device, final int sensorLocation) {
runOnUiThread(() -> {
if (sensorLocation >= SENSOR_LOCATION_FIRST && sensorLocation <= SENSOR_LOCATION_LAST) {
mHRSPosition.setText(getResources().getStringArray(R.array.hrs_locations)[sensorLocation]);
hrLocationView.setText(getResources().getStringArray(R.array.hrs_locations)[sensorLocation]);
} else {
mHRSPosition.setText(R.string.hrs_location_other);
hrLocationView.setText(R.string.hrs_location_other);
}
});
}
@Override
public void onHeartRateMeasurementReceived(@NonNull final BluetoothDevice device, final int heartRate,
public void onHeartRateMeasurementReceived(@NonNull final BluetoothDevice device,
@IntRange(from = 0) final int heartRate,
@Nullable final Boolean contactDetected,
@Nullable final Integer energyExpanded,
@Nullable @IntRange(from = 0) final Integer energyExpanded,
@Nullable final List<Integer> rrIntervals) {
mHrmValue = heartRate;
runOnUiThread(() -> mHRSValue.setText(getString(R.string.hrs_value, heartRate)));
hrValue = heartRate;
runOnUiThread(() -> hrValueView.setText(getString(R.string.hrs_value, heartRate)));
}
@Override
public void onDeviceDisconnected(@NonNull final BluetoothDevice device) {
super.onDeviceDisconnected(device);
runOnUiThread(() -> {
mHRSValue.setText(R.string.not_available_value);
mHRSPosition.setText(R.string.not_available);
mBatteryLevelView.setText(R.string.not_available);
hrValueView.setText(R.string.not_available_value);
hrLocationView.setText(R.string.not_available);
batteryLevelView.setText(R.string.not_available);
stopShowGraph();
});
}
@Override
protected void setDefaultUI() {
mHRSValue.setText(R.string.not_available_value);
mHRSPosition.setText(R.string.not_available);
mBatteryLevelView.setText(R.string.not_available);
hrValueView.setText(R.string.not_available_value);
hrLocationView.setText(R.string.not_available);
batteryLevelView.setText(R.string.not_available);
clearGraph();
}
private void clearGraph() {
mLineGraph.clearGraph();
mGraphView.repaint();
mCounter = 0;
mHrmValue = 0;
lineGraph.clearGraph();
graphView.repaint();
counter = 0;
hrValue = 0;
}
}

View File

@@ -26,6 +26,8 @@ import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.content.Context;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.util.Log;
@@ -35,6 +37,7 @@ import java.util.UUID;
import no.nordicsemi.android.ble.common.callback.hr.BodySensorLocationDataCallback;
import no.nordicsemi.android.ble.common.callback.hr.HeartRateMeasurementDataCallback;
import no.nordicsemi.android.ble.common.profile.hr.BodySensorLocation;
import no.nordicsemi.android.ble.data.Data;
import no.nordicsemi.android.log.LogContract;
import no.nordicsemi.android.nrftoolbox.battery.BatteryManager;
@@ -52,7 +55,7 @@ public class HRSManager extends BatteryManager<HRSManagerCallbacks> {
private static final UUID BODY_SENSOR_LOCATION_CHARACTERISTIC_UUID = UUID.fromString("00002A38-0000-1000-8000-00805f9b34fb");
private static final UUID HEART_RATE_MEASUREMENT_CHARACTERISTIC_UUID = UUID.fromString("00002A37-0000-1000-8000-00805f9b34fb");
private BluetoothGattCharacteristic mHeartRateCharacteristic, mBodySensorLocationCharacteristic;
private BluetoothGattCharacteristic heartRateCharacteristic, bodySensorLocationCharacteristic;
private static HRSManager managerInstance = null;
@@ -73,19 +76,19 @@ public class HRSManager extends BatteryManager<HRSManagerCallbacks> {
@NonNull
@Override
protected BatteryManagerGattCallback getGattCallback() {
return mGattCallback;
return gattCallback;
}
/**
* BluetoothGatt callbacks for connection/disconnection, service discovery,
* receiving notification, etc.
*/
private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() {
private final BatteryManagerGattCallback gattCallback = new BatteryManagerGattCallback() {
@Override
protected void initialize() {
super.initialize();
readCharacteristic(mBodySensorLocationCharacteristic)
readCharacteristic(bodySensorLocationCharacteristic)
.with(new BodySensorLocationDataCallback() {
@Override
public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
@@ -95,13 +98,13 @@ public class HRSManager extends BatteryManager<HRSManagerCallbacks> {
@Override
public void onBodySensorLocationReceived(@NonNull final BluetoothDevice device,
final int sensorLocation) {
mCallbacks.onBodySensorLocationReceived(device, sensorLocation);
@BodySensorLocation final int sensorLocation) {
callbacks.onBodySensorLocationReceived(device, sensorLocation);
}
})
.fail((device, status) -> log(Log.WARN, "Body Sensor Location characteristic not found"))
.enqueue();
setNotificationCallback(mHeartRateCharacteristic)
setNotificationCallback(heartRateCharacteristic)
.with(new HeartRateMeasurementDataCallback() {
@Override
public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
@@ -111,23 +114,23 @@ public class HRSManager extends BatteryManager<HRSManagerCallbacks> {
@Override
public void onHeartRateMeasurementReceived(@NonNull final BluetoothDevice device,
final int heartRate,
@IntRange(from = 0) final int heartRate,
@Nullable final Boolean contactDetected,
@Nullable final Integer energyExpanded,
@Nullable @IntRange(from = 0) final Integer energyExpanded,
@Nullable final List<Integer> rrIntervals) {
mCallbacks.onHeartRateMeasurementReceived(device, heartRate, contactDetected, energyExpanded, rrIntervals);
callbacks.onHeartRateMeasurementReceived(device, heartRate, contactDetected, energyExpanded, rrIntervals);
}
});
enableNotifications(mHeartRateCharacteristic).enqueue();
enableNotifications(heartRateCharacteristic).enqueue();
}
@Override
protected boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) {
final BluetoothGattService service = gatt.getService(HR_SERVICE_UUID);
if (service != null) {
mHeartRateCharacteristic = service.getCharacteristic(HEART_RATE_MEASUREMENT_CHARACTERISTIC_UUID);
heartRateCharacteristic = service.getCharacteristic(HEART_RATE_MEASUREMENT_CHARACTERISTIC_UUID);
}
return mHeartRateCharacteristic != null;
return heartRateCharacteristic != null;
}
@Override
@@ -135,16 +138,16 @@ public class HRSManager extends BatteryManager<HRSManagerCallbacks> {
super.isOptionalServiceSupported(gatt);
final BluetoothGattService service = gatt.getService(HR_SERVICE_UUID);
if (service != null) {
mBodySensorLocationCharacteristic = service.getCharacteristic(BODY_SENSOR_LOCATION_CHARACTERISTIC_UUID);
bodySensorLocationCharacteristic = service.getCharacteristic(BODY_SENSOR_LOCATION_CHARACTERISTIC_UUID);
}
return mBodySensorLocationCharacteristic != null;
return bodySensorLocationCharacteristic != null;
}
@Override
protected void onDeviceDisconnected() {
super.onDeviceDisconnected();
mBodySensorLocationCharacteristic = null;
mHeartRateCharacteristic = null;
bodySensorLocationCharacteristic = null;
heartRateCharacteristic = null;
}
};
}

View File

@@ -34,34 +34,37 @@ import org.achartengine.model.XYMultipleSeriesDataset;
import org.achartengine.renderer.XYMultipleSeriesRenderer;
import org.achartengine.renderer.XYSeriesRenderer;
import androidx.annotation.NonNull;
/**
* This class uses external library AChartEngine to show dynamic real time line graph for HR values
*/
public class LineGraphView {
class LineGraphView {
//TimeSeries will hold the data in x,y format for single chart
private TimeSeries mSeries = new TimeSeries("Heart Rate");
private TimeSeries series = new TimeSeries("Heart Rate");
//XYMultipleSeriesDataset will contain all the TimeSeries
private XYMultipleSeriesDataset mDataset = new XYMultipleSeriesDataset();
private XYMultipleSeriesDataset dataSet = new XYMultipleSeriesDataset();
//XYMultipleSeriesRenderer will contain all XYSeriesRenderer and it can be used to set the properties of whole Graph
private XYMultipleSeriesRenderer mMultiRenderer = new XYMultipleSeriesRenderer();
private static LineGraphView mInstance = null;
private XYMultipleSeriesRenderer multiRenderer = new XYMultipleSeriesRenderer();
private static LineGraphView instance = null;
/**
* singleton implementation of LineGraphView class
* Singleton implementation of LineGraphView class
*/
public static synchronized LineGraphView getLineGraphView() {
if (mInstance == null) {
mInstance = new LineGraphView();
@NonNull
static synchronized LineGraphView getLineGraphView() {
if (instance == null) {
instance = new LineGraphView();
}
return mInstance;
return instance;
}
/**
* This constructor will set some properties of single chart and some properties of whole graph
*/
public LineGraphView() {
//add single line chart mSeries
mDataset.addSeries(mSeries);
private LineGraphView() {
//add single line chart series
dataSet.addSeries(series);
//XYSeriesRenderer is used to set the properties like chart color, style of each point, etc. of single chart
final XYSeriesRenderer seriesRenderer = new XYSeriesRenderer();
@@ -71,7 +74,7 @@ public class LineGraphView {
seriesRenderer.setPointStyle(PointStyle.SQUARE);
seriesRenderer.setFillPoints(true);
final XYMultipleSeriesRenderer renderer = mMultiRenderer;
final XYMultipleSeriesRenderer renderer = multiRenderer;
//set whole graph background color to transparent color
renderer.setBackgroundColor(Color.TRANSPARENT);
renderer.setMargins(new int[] { 50, 65, 40, 5 }); // top, left, bottom, right
@@ -99,23 +102,22 @@ public class LineGraphView {
/**
* return graph view to activity
*/
public GraphicalView getView(Context context) {
final GraphicalView graphView = ChartFactory.getLineChartView(context, mDataset, mMultiRenderer);
return graphView;
GraphicalView getView(@NonNull final Context context) {
return ChartFactory.getLineChartView(context, dataSet, multiRenderer);
}
/**
* add new x,y value to chart
*/
public void addValue(Point p) {
mSeries.add(p.x, p.y);
void addValue(@NonNull final Point p) {
series.add(p.x, p.y);
}
/**
* clear all previous values of chart
*/
public void clearGraph() {
mSeries.clear();
void clearGraph() {
series.clear();
}
}

View File

@@ -29,6 +29,8 @@ import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import androidx.annotation.NonNull;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import android.view.Menu;
import android.widget.TextView;
@@ -50,9 +52,9 @@ public class HTSActivity extends BleProfileServiceReadyActivity<HTSService.HTSBi
@SuppressWarnings("unused")
private final String TAG = "HTSActivity";
private TextView mTempValue;
private TextView mUnit;
private TextView mBatteryLevelView;
private TextView tempValueView;
private TextView unitView;
private TextView batteryLevelView;
@Override
protected void onCreateView(final Bundle savedInstanceState) {
@@ -62,19 +64,19 @@ public class HTSActivity extends BleProfileServiceReadyActivity<HTSService.HTSBi
@Override
protected void onInitialize(final Bundle savedInstanceState) {
LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, makeIntentFilter());
LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, makeIntentFilter());
}
@Override
protected void onDestroy() {
super.onDestroy();
LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver);
LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver);
}
private void setGUI() {
mTempValue = findViewById(R.id.text_hts_value);
mUnit = findViewById(R.id.text_hts_unit);
mBatteryLevelView = findViewById(R.id.battery);
tempValueView = findViewById(R.id.text_hts_value);
unitView = findViewById(R.id.text_hts_unit);
batteryLevelView = findViewById(R.id.battery);
}
@Override
@@ -85,8 +87,8 @@ public class HTSActivity extends BleProfileServiceReadyActivity<HTSService.HTSBi
@Override
protected void setDefaultUI() {
mTempValue.setText(R.string.not_available_value);
mBatteryLevelView.setText(R.string.not_available);
tempValueView.setText(R.string.not_available_value);
batteryLevelView.setText(R.string.not_available);
setUnits();
}
@@ -97,13 +99,13 @@ public class HTSActivity extends BleProfileServiceReadyActivity<HTSService.HTSBi
switch (unit) {
case SettingsFragment.SETTINGS_UNIT_C:
mUnit.setText(R.string.hts_unit_celsius);
this.unitView.setText(R.string.hts_unit_celsius);
break;
case SettingsFragment.SETTINGS_UNIT_F:
mUnit.setText(R.string.hts_unit_fahrenheit);
this.unitView.setText(R.string.hts_unit_fahrenheit);
break;
case SettingsFragment.SETTINGS_UNIT_K:
mUnit.setText(R.string.hts_unit_kelvin);
this.unitView.setText(R.string.hts_unit_kelvin);
break;
}
}
@@ -161,14 +163,14 @@ public class HTSActivity extends BleProfileServiceReadyActivity<HTSService.HTSBi
}
@Override
public void onServicesDiscovered(final BluetoothDevice device, boolean optionalServicesFound) {
public void onServicesDiscovered(@NonNull final BluetoothDevice device, boolean optionalServicesFound) {
// this may notify user or show some views
}
@Override
public void onDeviceDisconnected(final BluetoothDevice device) {
public void onDeviceDisconnected(@NonNull final BluetoothDevice device) {
super.onDeviceDisconnected(device);
mBatteryLevelView.setText(R.string.not_available);
batteryLevelView.setText(R.string.not_available);
}
private void onTemperatureMeasurementReceived(Float value) {
@@ -187,17 +189,17 @@ public class HTSActivity extends BleProfileServiceReadyActivity<HTSService.HTSBi
case SettingsFragment.SETTINGS_UNIT_C:
break;
}
mTempValue.setText(getString(R.string.hts_value, value));
tempValueView.setText(getString(R.string.hts_value, value));
} else {
mTempValue.setText(R.string.not_available_value);
tempValueView.setText(R.string.not_available_value);
}
}
public void onBatteryLevelChanged(final int value) {
mBatteryLevelView.setText(getString(R.string.battery, value));
batteryLevelView.setText(getString(R.string.battery, value));
}
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
final String action = intent.getAction();

View File

@@ -33,6 +33,8 @@ import java.util.Calendar;
import java.util.UUID;
import no.nordicsemi.android.ble.common.callback.ht.TemperatureMeasurementDataCallback;
import no.nordicsemi.android.ble.common.profile.ht.TemperatureType;
import no.nordicsemi.android.ble.common.profile.ht.TemperatureUnit;
import no.nordicsemi.android.ble.data.Data;
import no.nordicsemi.android.log.LogContract;
import no.nordicsemi.android.nrftoolbox.battery.BatteryManager;
@@ -46,11 +48,11 @@ import no.nordicsemi.android.nrftoolbox.parser.TemperatureMeasurementParser;
*/
public class HTSManager extends BatteryManager<HTSManagerCallbacks> {
/** Health Thermometer service UUID */
public final static UUID HT_SERVICE_UUID = UUID.fromString("00001809-0000-1000-8000-00805f9b34fb");
final static UUID HT_SERVICE_UUID = UUID.fromString("00001809-0000-1000-8000-00805f9b34fb");
/** Health Thermometer Measurement characteristic UUID */
private static final UUID HT_MEASUREMENT_CHARACTERISTIC_UUID = UUID.fromString("00002A1C-0000-1000-8000-00805f9b34fb");
private BluetoothGattCharacteristic mHTCharacteristic;
private BluetoothGattCharacteristic htCharacteristic;
HTSManager(final Context context) {
super(context);
@@ -59,18 +61,18 @@ public class HTSManager extends BatteryManager<HTSManagerCallbacks> {
@NonNull
@Override
protected BatteryManagerGattCallback getGattCallback() {
return mGattCallback;
return gattCallback;
}
/**
* BluetoothGatt callbacks for connection/disconnection, service discovery,
* receiving indication, etc..
*/
private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() {
private final BatteryManagerGattCallback gattCallback = new BatteryManagerGattCallback() {
@Override
protected void initialize() {
super.initialize();
setIndicationCallback(mHTCharacteristic)
setIndicationCallback(htCharacteristic)
.with(new TemperatureMeasurementDataCallback() {
@Override
public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
@@ -80,28 +82,28 @@ public class HTSManager extends BatteryManager<HTSManagerCallbacks> {
@Override
public void onTemperatureMeasurementReceived(@NonNull final BluetoothDevice device,
final float temperature, final int unit,
final float temperature, @TemperatureUnit final int unit,
@Nullable final Calendar calendar,
@Nullable final Integer type) {
mCallbacks.onTemperatureMeasurementReceived(device, temperature, unit, calendar, type);
@Nullable @TemperatureType final Integer type) {
callbacks.onTemperatureMeasurementReceived(device, temperature, unit, calendar, type);
}
});
enableIndications(mHTCharacteristic).enqueue();
enableIndications(htCharacteristic).enqueue();
}
@Override
protected boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) {
final BluetoothGattService service = gatt.getService(HT_SERVICE_UUID);
if (service != null) {
mHTCharacteristic = service.getCharacteristic(HT_MEASUREMENT_CHARACTERISTIC_UUID);
htCharacteristic = service.getCharacteristic(HT_MEASUREMENT_CHARACTERISTIC_UUID);
}
return mHTCharacteristic != null;
return htCharacteristic != null;
}
@Override
protected void onDeviceDisconnected() {
super.onDeviceDisconnected();
mHTCharacteristic = null;
htCharacteristic = null;
}
};
}

View File

@@ -40,6 +40,8 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import java.util.Calendar;
import no.nordicsemi.android.ble.common.profile.ht.TemperatureMeasurementCallback;
import no.nordicsemi.android.ble.common.profile.ht.TemperatureType;
import no.nordicsemi.android.ble.common.profile.ht.TemperatureUnit;
import no.nordicsemi.android.log.Logger;
import no.nordicsemi.android.nrftoolbox.FeaturesActivity;
import no.nordicsemi.android.nrftoolbox.R;
@@ -61,12 +63,12 @@ public class HTSService extends BleProfileService implements HTSManagerCallbacks
private final static int OPEN_ACTIVITY_REQ = 0;
private final static int DISCONNECT_REQ = 1;
/** The last received temperature value in Celsius degrees. */
private Float mTemp;
private Float temp;
@SuppressWarnings("unused")
private HTSManager mManager;
private HTSManager manager;
private final LocalBinder mBinder = new HTSBinder();
private final LocalBinder minder = new HTSBinder();
/**
* This local binder is an interface for the bonded activity to operate with the HTS sensor
@@ -78,18 +80,18 @@ public class HTSService extends BleProfileService implements HTSManagerCallbacks
* @return Temperature value in Celsius.
*/
Float getTemperature() {
return mTemp;
return temp;
}
}
@Override
protected LocalBinder getBinder() {
return mBinder;
return minder;
}
@Override
protected LoggableBleManager<HTSManagerCallbacks> initializeManager() {
return mManager = new HTSManager(this);
return manager = new HTSManager(this);
}
@Override
@@ -98,14 +100,14 @@ public class HTSService extends BleProfileService implements HTSManagerCallbacks
final IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_DISCONNECT);
registerReceiver(mDisconnectActionBroadcastReceiver, filter);
registerReceiver(disconnectActionBroadcastReceiver, filter);
}
@Override
public void onDestroy() {
// when user has disconnected from the sensor, we have to cancel the notification that we've created some milliseconds before using unbindService
cancelNotification();
unregisterReceiver(mDisconnectActionBroadcastReceiver);
unregisterReceiver(disconnectActionBroadcastReceiver);
super.onDestroy();
}
@@ -121,25 +123,25 @@ public class HTSService extends BleProfileService implements HTSManagerCallbacks
}
@Override
public void onDeviceDisconnected(final BluetoothDevice device) {
public void onDeviceDisconnected(@NonNull final BluetoothDevice device) {
super.onDeviceDisconnected(device);
mTemp = null;
temp = null;
}
@Override
public void onTemperatureMeasurementReceived(@NonNull final BluetoothDevice device,
final float temperature, final int unit,
final float temperature, @TemperatureUnit final int unit,
@Nullable final Calendar calendar,
@Nullable final Integer type) {
mTemp = TemperatureMeasurementCallback.toCelsius(temperature, unit);
@Nullable @TemperatureType final Integer type) {
temp = TemperatureMeasurementCallback.toCelsius(temperature, unit);
final Intent broadcast = new Intent(BROADCAST_HTS_MEASUREMENT);
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
broadcast.putExtra(EXTRA_TEMPERATURE, mTemp);
broadcast.putExtra(EXTRA_TEMPERATURE, temp);
// ignore the rest
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
if (!mBound) {
if (!bound) {
// Here we may update the notification to display the current temperature.
// TODO modify the notification here
}
@@ -188,6 +190,7 @@ public class HTSService extends BleProfileService implements HTSManagerCallbacks
* f.e. <code>&lt;string name="name"&gt;%s is connected&lt;/string&gt;</code>
* @param defaults
*/
@SuppressWarnings("SameParameterValue")
private Notification createNotification(final int messageResId, final int defaults) {
final Intent parentIntent = new Intent(this, FeaturesActivity.class);
parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -219,7 +222,7 @@ public class HTSService extends BleProfileService implements HTSManagerCallbacks
/**
* This broadcast receiver listens for {@link #ACTION_DISCONNECT} that may be fired by pressing Disconnect action button on the notification.
*/
private final BroadcastReceiver mDisconnectActionBroadcastReceiver = new BroadcastReceiver() {
private final BroadcastReceiver disconnectActionBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
Logger.i(getLogSession(), "[Notification] Disconnect action pressed");

View File

@@ -30,6 +30,7 @@ import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import android.view.Menu;
@@ -58,17 +59,17 @@ public abstract class BleProfileActivity extends AppCompatActivity implements Bl
private static final String SIS_DEVICE_NAME = "device_name";
protected static final int REQUEST_ENABLE_BT = 2;
private LoggableBleManager<? extends BleManagerCallbacks> mBleManager;
private LoggableBleManager<? extends BleManagerCallbacks> bleManager;
private TextView mDeviceNameView;
private Button mConnectButton;
private ILogSession mLogSession;
private TextView deviceNameView;
private Button connectButton;
private ILogSession logSession;
private boolean mDeviceConnected = false;
private String mDeviceName;
private boolean deviceConnected = false;
private String deviceName;
@Override
protected final void onCreate(final Bundle savedInstanceState) {
protected final void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ensureBLESupported();
@@ -82,7 +83,7 @@ public abstract class BleProfileActivity extends AppCompatActivity implements Bl
* Services. The Service should implement ManagerCallbacks interface. The application Activity may communicate with such Service using binding,
* broadcast listeners, local broadcast listeners (see support.v4 library), or messages. See the Proximity profile for Service approach.
*/
mBleManager = initializeManager();
bleManager = initializeManager();
// In onInitialize method a final class may register local broadcast receivers that will listen for events from the service
onInitialize(savedInstanceState);
@@ -101,7 +102,7 @@ public abstract class BleProfileActivity extends AppCompatActivity implements Bl
/**
* You may do some initialization here. This method is called from {@link #onCreate(Bundle)} before the view was created.
*/
protected void onInitialize(final Bundle savedInstanceState) {
protected void onInitialize(@Nullable final Bundle savedInstanceState) {
// empty default implementation
}
@@ -112,7 +113,7 @@ public abstract class BleProfileActivity extends AppCompatActivity implements Bl
* @param savedInstanceState contains the data it most recently supplied in {@link #onSaveInstanceState(Bundle)}.
* Note: <b>Otherwise it is null</b>.
*/
protected abstract void onCreateView(final Bundle savedInstanceState);
protected abstract void onCreateView(@Nullable final Bundle savedInstanceState);
/**
* Called after the view has been created.
@@ -120,7 +121,7 @@ public abstract class BleProfileActivity extends AppCompatActivity implements Bl
* @param savedInstanceState contains the data it most recently supplied in {@link #onSaveInstanceState(Bundle)}.
* Note: <b>Otherwise it is null</b>.
*/
protected void onViewCreated(final Bundle savedInstanceState) {
protected void onViewCreated(@Nullable final Bundle savedInstanceState) {
// empty default implementation
}
@@ -130,33 +131,33 @@ public abstract class BleProfileActivity extends AppCompatActivity implements Bl
protected final void setUpView() {
// set GUI
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
mConnectButton = findViewById(R.id.action_connect);
mDeviceNameView = findViewById(R.id.device_name);
connectButton = findViewById(R.id.action_connect);
deviceNameView = findViewById(R.id.device_name);
}
@Override
public void onBackPressed() {
mBleManager.disconnect().enqueue();
bleManager.disconnect().enqueue();
super.onBackPressed();
}
@Override
protected void onSaveInstanceState(final Bundle outState) {
protected void onSaveInstanceState(@NonNull final Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(SIS_CONNECTION_STATUS, mDeviceConnected);
outState.putString(SIS_DEVICE_NAME, mDeviceName);
outState.putBoolean(SIS_CONNECTION_STATUS, deviceConnected);
outState.putString(SIS_DEVICE_NAME, deviceName);
}
@Override
protected void onRestoreInstanceState(final @NonNull Bundle savedInstanceState) {
protected void onRestoreInstanceState(@NonNull final Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mDeviceConnected = savedInstanceState.getBoolean(SIS_CONNECTION_STATUS);
mDeviceName = savedInstanceState.getString(SIS_DEVICE_NAME);
deviceConnected = savedInstanceState.getBoolean(SIS_CONNECTION_STATUS);
deviceName = savedInstanceState.getString(SIS_DEVICE_NAME);
if (mDeviceConnected) {
mConnectButton.setText(R.string.action_disconnect);
if (deviceConnected) {
connectButton.setText(R.string.action_disconnect);
} else {
mConnectButton.setText(R.string.action_connect);
connectButton.setText(R.string.action_connect);
}
}
@@ -178,7 +179,7 @@ public abstract class BleProfileActivity extends AppCompatActivity implements Bl
}
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
public boolean onOptionsItemSelected(@NonNull final MenuItem item) {
final int id = item.getItemId();
switch (id) {
case android.R.id.home:
@@ -199,11 +200,11 @@ public abstract class BleProfileActivity extends AppCompatActivity implements Bl
*/
public void onConnectClicked(final View view) {
if (isBLEEnabled()) {
if (!mDeviceConnected) {
if (!deviceConnected) {
setDefaultUI();
showDeviceScanningDialog(getFilterUUID());
} else {
mBleManager.disconnect().enqueue();
bleManager.disconnect().enqueue();
}
} else {
showBLEDialog();
@@ -238,18 +239,18 @@ public abstract class BleProfileActivity extends AppCompatActivity implements Bl
}
@Override
public void onDeviceSelected(final BluetoothDevice device, final String name) {
public void onDeviceSelected(@NonNull final BluetoothDevice device, final String name) {
final int titleId = getLoggerProfileTitle();
if (titleId > 0) {
mLogSession = Logger.newSession(getApplicationContext(), getString(titleId), device.getAddress(), name);
logSession = Logger.newSession(getApplicationContext(), getString(titleId), device.getAddress(), name);
// If nRF Logger is not installed we may want to use local logger
if (mLogSession == null && getLocalAuthorityLogger() != null) {
mLogSession = LocalLogSession.newSession(getApplicationContext(), getLocalAuthorityLogger(), device.getAddress(), name);
if (logSession == null && getLocalAuthorityLogger() != null) {
logSession = LocalLogSession.newSession(getApplicationContext(), getLocalAuthorityLogger(), device.getAddress(), name);
}
}
mDeviceName = name;
mBleManager.setLogger(mLogSession);
mBleManager.connect(device)
deviceName = name;
bleManager.setLogger(logSession);
bleManager.connect(device)
.useAutoConnect(shouldAutoConnect())
.retry(3, 100)
.enqueue();
@@ -263,35 +264,35 @@ public abstract class BleProfileActivity extends AppCompatActivity implements Bl
@Override
public void onDeviceConnecting(@NonNull final BluetoothDevice device) {
runOnUiThread(() -> {
mDeviceNameView.setText(mDeviceName != null ? mDeviceName : getString(R.string.not_available));
mConnectButton.setText(R.string.action_connecting);
deviceNameView.setText(deviceName != null ? deviceName : getString(R.string.not_available));
connectButton.setText(R.string.action_connecting);
});
}
@Override
public void onDeviceConnected(@NonNull final BluetoothDevice device) {
mDeviceConnected = true;
runOnUiThread(() -> mConnectButton.setText(R.string.action_disconnect));
deviceConnected = true;
runOnUiThread(() -> connectButton.setText(R.string.action_disconnect));
}
@Override
public void onDeviceDisconnecting(@NonNull final BluetoothDevice device) {
runOnUiThread(() -> mConnectButton.setText(R.string.action_disconnecting));
runOnUiThread(() -> connectButton.setText(R.string.action_disconnecting));
}
@Override
public void onDeviceDisconnected(@NonNull final BluetoothDevice device) {
mDeviceConnected = false;
mBleManager.close();
deviceConnected = false;
bleManager.close();
runOnUiThread(() -> {
mConnectButton.setText(R.string.action_connect);
mDeviceNameView.setText(getDefaultDeviceName());
connectButton.setText(R.string.action_connect);
deviceNameView.setText(getDefaultDeviceName());
});
}
@Override
public void onLinkLossOccurred(@NonNull final BluetoothDevice device) {
mDeviceConnected = false;
deviceConnected = false;
}
@Override
@@ -352,14 +353,14 @@ public abstract class BleProfileActivity extends AppCompatActivity implements Bl
* Returns <code>true</code> if the device is connected. Services may not have been discovered yet.
*/
protected boolean isDeviceConnected() {
return mDeviceConnected;
return deviceConnected;
}
/**
* Returns the name of the device that the phone is currently connected to or was connected last time
*/
protected String getDeviceName() {
return mDeviceName;
return deviceName;
}
/**
@@ -417,7 +418,7 @@ public abstract class BleProfileActivity extends AppCompatActivity implements Bl
* @return the logger session or <code>null</code>
*/
protected ILogSession getLogSession() {
return mLogSession;
return logSession;
}
private void ensureBLESupported() {

View File

@@ -58,14 +58,14 @@ public abstract class BleProfileExpandableListActivity extends ExpandableListAct
private static final String SIS_DEVICE_NAME = "device_name";
protected static final int REQUEST_ENABLE_BT = 2;
private LoggableBleManager<? extends BleManagerCallbacks> mBleManager;
private LoggableBleManager<? extends BleManagerCallbacks> bleManager;
private TextView mDeviceNameView;
private Button mConnectButton;
private ILogSession mLogSession;
private TextView deviceNameView;
private Button connectButton;
private ILogSession logSession;
private boolean mDeviceConnected = false;
private String mDeviceName;
private boolean deviceConnected = false;
private String deviceName;
@Override
protected final void onCreate(final Bundle savedInstanceState) {
@@ -82,7 +82,7 @@ public abstract class BleProfileExpandableListActivity extends ExpandableListAct
* Services. The Service should implement ManagerCallbacks interface. The application Activity may communicate with such Service using binding,
* broadcast listeners, local broadcast listeners (see support.v4 library), or messages. See the Proximity profile for Service approach.
*/
mBleManager = initializeManager();
bleManager = initializeManager();
// In onInitialize method a final class may register local broadcast receivers that will listen for events from the service
onInitialize(savedInstanceState);
@@ -132,33 +132,33 @@ public abstract class BleProfileExpandableListActivity extends ExpandableListAct
protected final void setUpView() {
// set GUI
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
mConnectButton = findViewById(R.id.action_connect);
mDeviceNameView = findViewById(R.id.device_name);
connectButton = findViewById(R.id.action_connect);
deviceNameView = findViewById(R.id.device_name);
}
@Override
public void onBackPressed() {
mBleManager.disconnect().enqueue();
bleManager.disconnect().enqueue();
super.onBackPressed();
}
@Override
protected void onSaveInstanceState(final Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(SIS_CONNECTION_STATUS, mDeviceConnected);
outState.putString(SIS_DEVICE_NAME, mDeviceName);
outState.putBoolean(SIS_CONNECTION_STATUS, deviceConnected);
outState.putString(SIS_DEVICE_NAME, deviceName);
}
@Override
protected void onRestoreInstanceState(final @NonNull Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mDeviceConnected = savedInstanceState.getBoolean(SIS_CONNECTION_STATUS);
mDeviceName = savedInstanceState.getString(SIS_DEVICE_NAME);
deviceConnected = savedInstanceState.getBoolean(SIS_CONNECTION_STATUS);
deviceName = savedInstanceState.getString(SIS_DEVICE_NAME);
if (mDeviceConnected) {
mConnectButton.setText(R.string.action_disconnect);
if (deviceConnected) {
connectButton.setText(R.string.action_disconnect);
} else {
mConnectButton.setText(R.string.action_connect);
connectButton.setText(R.string.action_connect);
}
}
@@ -202,11 +202,11 @@ public abstract class BleProfileExpandableListActivity extends ExpandableListAct
*/
public void onConnectClicked(final View view) {
if (isBLEEnabled()) {
if (!mDeviceConnected) {
if (!deviceConnected) {
setDefaultUI();
showDeviceScanningDialog(getFilterUUID());
} else {
mBleManager.disconnect().enqueue();
bleManager.disconnect().enqueue();
}
} else {
showBLEDialog();
@@ -241,18 +241,18 @@ public abstract class BleProfileExpandableListActivity extends ExpandableListAct
}
@Override
public void onDeviceSelected(final BluetoothDevice device, final String name) {
public void onDeviceSelected(@NonNull final BluetoothDevice device, final String name) {
final int titleId = getLoggerProfileTitle();
if (titleId > 0) {
mLogSession = Logger.newSession(getApplicationContext(), getString(titleId), device.getAddress(), name);
logSession = Logger.newSession(getApplicationContext(), getString(titleId), device.getAddress(), name);
// If nRF Logger is not installed we may want to use local logger
if (mLogSession == null && getLocalAuthorityLogger() != null) {
mLogSession = LocalLogSession.newSession(getApplicationContext(), getLocalAuthorityLogger(), device.getAddress(), name);
if (logSession == null && getLocalAuthorityLogger() != null) {
logSession = LocalLogSession.newSession(getApplicationContext(), getLocalAuthorityLogger(), device.getAddress(), name);
}
}
mDeviceName = name;
mBleManager.setLogger(mLogSession);
mBleManager.connect(device)
deviceName = name;
bleManager.setLogger(logSession);
bleManager.connect(device)
.useAutoConnect(shouldAutoConnect())
.retry(3, 100)
.enqueue();
@@ -266,35 +266,35 @@ public abstract class BleProfileExpandableListActivity extends ExpandableListAct
@Override
public void onDeviceConnecting(@NonNull final BluetoothDevice device) {
runOnUiThread(() -> {
mDeviceNameView.setText(mDeviceName != null ? mDeviceName : getString(R.string.not_available));
mConnectButton.setText(R.string.action_connecting);
deviceNameView.setText(deviceName != null ? deviceName : getString(R.string.not_available));
connectButton.setText(R.string.action_connecting);
});
}
@Override
public void onDeviceConnected(@NonNull final BluetoothDevice device) {
mDeviceConnected = true;
runOnUiThread(() -> mConnectButton.setText(R.string.action_disconnect));
deviceConnected = true;
runOnUiThread(() -> connectButton.setText(R.string.action_disconnect));
}
@Override
public void onDeviceDisconnecting(@NonNull final BluetoothDevice device) {
runOnUiThread(() -> mConnectButton.setText(R.string.action_disconnecting));
runOnUiThread(() -> connectButton.setText(R.string.action_disconnecting));
}
@Override
public void onDeviceDisconnected(@NonNull final BluetoothDevice device) {
mDeviceConnected = false;
mBleManager.close();
deviceConnected = false;
bleManager.close();
runOnUiThread(() -> {
mConnectButton.setText(R.string.action_connect);
mDeviceNameView.setText(getDefaultDeviceName());
connectButton.setText(R.string.action_connect);
deviceNameView.setText(getDefaultDeviceName());
});
}
@Override
public void onLinkLossOccurred(@NonNull final BluetoothDevice device) {
mDeviceConnected = false;
deviceConnected = false;
}
@Override
@@ -355,14 +355,14 @@ public abstract class BleProfileExpandableListActivity extends ExpandableListAct
* Returns <code>true</code> if the device is connected. Services may not have been discovered yet.
*/
protected boolean isDeviceConnected() {
return mDeviceConnected;
return deviceConnected;
}
/**
* Returns the name of the device that the phone is currently connected to or was connected last time
*/
protected String getDeviceName() {
return mDeviceName;
return deviceName;
}
/**
@@ -420,7 +420,7 @@ public abstract class BleProfileExpandableListActivity extends ExpandableListAct
* @return the logger session or <code>null</code>
*/
protected ILogSession getLogSession() {
return mLogSession;
return logSession;
}
private void ensureBLESupported() {

View File

@@ -83,16 +83,16 @@ public abstract class BleProfileService extends Service implements BleManagerCal
public static final int STATE_CONNECTING = 2;
public static final int STATE_DISCONNECTING = 3;
private LoggableBleManager<BleManagerCallbacks> mBleManager;
private Handler mHandler;
private LoggableBleManager<BleManagerCallbacks> bleManager;
private Handler handler;
protected boolean mBound;
private boolean mActivityIsChangingConfiguration;
private BluetoothDevice mBluetoothDevice;
private String mDeviceName;
private ILogSession mLogSession;
protected boolean bound;
private boolean activityIsChangingConfiguration;
private BluetoothDevice bluetoothDevice;
private String deviceName;
private ILogSession logSession;
private final BroadcastReceiver mBluetoothStateBroadcastReceiver = new BroadcastReceiver() {
private final BroadcastReceiver bluetoothStateBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF);
@@ -133,14 +133,14 @@ public abstract class BleProfileService extends Service implements BleManagerCal
* Disconnects from the sensor.
*/
public final void disconnect() {
final int state = mBleManager.getConnectionState();
final int state = bleManager.getConnectionState();
if (state == BluetoothGatt.STATE_DISCONNECTED || state == BluetoothGatt.STATE_DISCONNECTING) {
mBleManager.close();
onDeviceDisconnected(mBluetoothDevice);
bleManager.close();
onDeviceDisconnected(bluetoothDevice);
return;
}
mBleManager.disconnect().enqueue();
bleManager.disconnect().enqueue();
}
/**
@@ -150,7 +150,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
* @param changing true if the bound activity is finishing
*/
public void setActivityIsChangingConfiguration(final boolean changing) {
mActivityIsChangingConfiguration = changing;
activityIsChangingConfiguration = changing;
}
/**
@@ -159,7 +159,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
* @return device address
*/
public String getDeviceAddress() {
return mBluetoothDevice.getAddress();
return bluetoothDevice.getAddress();
}
/**
@@ -168,7 +168,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
* @return the device name
*/
public String getDeviceName() {
return mDeviceName;
return deviceName;
}
/**
@@ -177,7 +177,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
* @return the Bluetooth device
*/
public BluetoothDevice getBluetoothDevice() {
return mBluetoothDevice;
return bluetoothDevice;
}
/**
@@ -186,7 +186,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
* @return <code>true</code> if device is connected to the sensor, <code>false</code> otherwise
*/
public boolean isConnected() {
return mBleManager.isConnected();
return bleManager.isConnected();
}
@@ -196,7 +196,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
* @return the connection state, as in {@link BleManager#getConnectionState()}.
*/
public int getConnectionState() {
return mBleManager.getConnectionState();
return bleManager.getConnectionState();
}
/**
@@ -207,17 +207,17 @@ public abstract class BleProfileService extends Service implements BleManagerCal
* @return the log session
*/
public ILogSession getLogSession() {
return mLogSession;
return logSession;
}
@Override
public void log(final int level, @NonNull final String message) {
Logger.log(mLogSession, level, message);
Logger.log(logSession, level, message);
}
@Override
public void log(final int level, final @StringRes int messageRes, final Object... params) {
Logger.log(mLogSession, level, messageRes, params);
Logger.log(logSession, level, messageRes, params);
}
}
@@ -226,7 +226,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
* The handler may be used to postpone execution of some operations or to run them in UI thread.
*/
protected Handler getHandler() {
return mHandler;
return handler;
}
/**
@@ -241,15 +241,15 @@ public abstract class BleProfileService extends Service implements BleManagerCal
@Override
public IBinder onBind(final Intent intent) {
mBound = true;
bound = true;
return getBinder();
}
@Override
public final void onRebind(final Intent intent) {
mBound = true;
bound = true;
if (!mActivityIsChangingConfiguration)
if (!activityIsChangingConfiguration)
onRebind();
}
@@ -264,9 +264,9 @@ public abstract class BleProfileService extends Service implements BleManagerCal
@Override
public final boolean onUnbind(final Intent intent) {
mBound = false;
bound = false;
if (!mActivityIsChangingConfiguration)
if (!activityIsChangingConfiguration)
onUnbind();
// We want the onRebind method be called if anything else binds to it again
@@ -286,14 +286,14 @@ public abstract class BleProfileService extends Service implements BleManagerCal
public void onCreate() {
super.onCreate();
mHandler = new Handler();
handler = new Handler();
// Initialize the manager
mBleManager = initializeManager();
mBleManager.setGattCallbacks(this);
bleManager = initializeManager();
bleManager.setGattCallbacks(this);
// Register broadcast receivers
registerReceiver(mBluetoothStateBroadcastReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
registerReceiver(bluetoothStateBroadcastReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
// Service has now been created
onServiceCreated();
@@ -335,18 +335,18 @@ public abstract class BleProfileService extends Service implements BleManagerCal
throw new UnsupportedOperationException("No device address at EXTRA_DEVICE_ADDRESS key");
final Uri logUri = intent.getParcelableExtra(EXTRA_LOG_URI);
mLogSession = Logger.openSession(getApplicationContext(), logUri);
mDeviceName = intent.getStringExtra(EXTRA_DEVICE_NAME);
logSession = Logger.openSession(getApplicationContext(), logUri);
deviceName = intent.getStringExtra(EXTRA_DEVICE_NAME);
Logger.i(mLogSession, "Service started");
Logger.i(logSession, "Service started");
final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
final String deviceAddress = intent.getStringExtra(EXTRA_DEVICE_ADDRESS);
mBluetoothDevice = adapter.getRemoteDevice(deviceAddress);
bluetoothDevice = adapter.getRemoteDevice(deviceAddress);
mBleManager.setLogger(mLogSession);
bleManager.setLogger(logSession);
onServiceStarted();
mBleManager.connect(mBluetoothDevice)
bleManager.connect(bluetoothDevice)
.useAutoConnect(shouldAutoConnect())
.retry(3, 100)
.enqueue();
@@ -374,16 +374,16 @@ public abstract class BleProfileService extends Service implements BleManagerCal
public void onDestroy() {
super.onDestroy();
// Unregister broadcast receivers
unregisterReceiver(mBluetoothStateBroadcastReceiver);
unregisterReceiver(bluetoothStateBroadcastReceiver);
// shutdown the manager
mBleManager.close();
Logger.i(mLogSession, "Service destroyed");
mBleManager = null;
mBluetoothDevice = null;
mDeviceName = null;
mLogSession = null;
mHandler = null;
bleManager.close();
Logger.i(logSession, "Service destroyed");
bleManager = null;
bluetoothDevice = null;
deviceName = null;
logSession = null;
handler = null;
}
/**
@@ -405,7 +405,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
@Override
public void onDeviceConnecting(@NonNull final BluetoothDevice device) {
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
broadcast.putExtra(EXTRA_DEVICE, bluetoothDevice);
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_CONNECTING);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
}
@@ -414,8 +414,8 @@ public abstract class BleProfileService extends Service implements BleManagerCal
public void onDeviceConnected(@NonNull final BluetoothDevice device) {
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_CONNECTED);
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
broadcast.putExtra(EXTRA_DEVICE_NAME, mDeviceName);
broadcast.putExtra(EXTRA_DEVICE, bluetoothDevice);
broadcast.putExtra(EXTRA_DEVICE_NAME, deviceName);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
}
@@ -423,7 +423,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
public void onDeviceDisconnecting(@NonNull final BluetoothDevice device) {
// Notify user about changing the state to DISCONNECTING
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
broadcast.putExtra(EXTRA_DEVICE, bluetoothDevice);
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_DISCONNECTING);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
}
@@ -447,7 +447,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
// disconnects due to a link loss, the onLinkLossOccurred(BluetoothDevice) method will be called instead.
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
broadcast.putExtra(EXTRA_DEVICE, bluetoothDevice);
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_DISCONNECTED);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
@@ -457,14 +457,14 @@ public abstract class BleProfileService extends Service implements BleManagerCal
protected void stopService() {
// user requested disconnection. We must stop the service
Logger.v(mLogSession, "Stopping service...");
Logger.v(logSession, "Stopping service...");
stopSelf();
}
@Override
public void onLinkLossOccurred(@NonNull final BluetoothDevice device) {
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
broadcast.putExtra(EXTRA_DEVICE, bluetoothDevice);
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_LINK_LOSS);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
}
@@ -472,7 +472,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
@Override
public void onServicesDiscovered(@NonNull final BluetoothDevice device, final boolean optionalServicesFound) {
final Intent broadcast = new Intent(BROADCAST_SERVICES_DISCOVERED);
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
broadcast.putExtra(EXTRA_DEVICE, bluetoothDevice);
broadcast.putExtra(EXTRA_SERVICE_PRIMARY, true);
broadcast.putExtra(EXTRA_SERVICE_SECONDARY, optionalServicesFound);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
@@ -481,14 +481,14 @@ public abstract class BleProfileService extends Service implements BleManagerCal
@Override
public void onDeviceReady(@NonNull final BluetoothDevice device) {
final Intent broadcast = new Intent(BROADCAST_DEVICE_READY);
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
broadcast.putExtra(EXTRA_DEVICE, bluetoothDevice);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
}
@Override
public void onDeviceNotSupported(@NonNull final BluetoothDevice device) {
final Intent broadcast = new Intent(BROADCAST_SERVICES_DISCOVERED);
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
broadcast.putExtra(EXTRA_DEVICE, bluetoothDevice);
broadcast.putExtra(EXTRA_SERVICE_PRIMARY, false);
broadcast.putExtra(EXTRA_SERVICE_SECONDARY, false);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
@@ -499,7 +499,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
@Override
public void onBatteryValueReceived(@NonNull final BluetoothDevice device, final int value) {
final Intent broadcast = new Intent(BROADCAST_BATTERY_LEVEL);
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
broadcast.putExtra(EXTRA_DEVICE, bluetoothDevice);
broadcast.putExtra(EXTRA_BATTERY_LEVEL, value);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
}
@@ -509,7 +509,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
showToast(no.nordicsemi.android.nrftoolbox.common.R.string.bonding);
final Intent broadcast = new Intent(BROADCAST_BOND_STATE);
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
broadcast.putExtra(EXTRA_DEVICE, bluetoothDevice);
broadcast.putExtra(EXTRA_BOND_STATE, BluetoothDevice.BOND_BONDING);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
}
@@ -519,7 +519,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
showToast(no.nordicsemi.android.nrftoolbox.common.R.string.bonded);
final Intent broadcast = new Intent(BROADCAST_BOND_STATE);
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
broadcast.putExtra(EXTRA_DEVICE, bluetoothDevice);
broadcast.putExtra(EXTRA_BOND_STATE, BluetoothDevice.BOND_BONDED);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
}
@@ -529,7 +529,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
showToast(no.nordicsemi.android.nrftoolbox.common.R.string.bonding_failed);
final Intent broadcast = new Intent(BROADCAST_BOND_STATE);
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
broadcast.putExtra(EXTRA_DEVICE, bluetoothDevice);
broadcast.putExtra(EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
}
@@ -537,7 +537,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
@Override
public void onError(@NonNull final BluetoothDevice device, @NonNull final String message, final int errorCode) {
final Intent broadcast = new Intent(BROADCAST_ERROR);
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
broadcast.putExtra(EXTRA_DEVICE, bluetoothDevice);
broadcast.putExtra(EXTRA_ERROR_MESSAGE, message);
broadcast.putExtra(EXTRA_ERROR_CODE, errorCode);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
@@ -549,7 +549,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
* @param messageResId an resource id of the message to be shown
*/
protected void showToast(final int messageResId) {
mHandler.post(() -> Toast.makeText(BleProfileService.this, messageResId, Toast.LENGTH_SHORT).show());
handler.post(() -> Toast.makeText(BleProfileService.this, messageResId, Toast.LENGTH_SHORT).show());
}
/**
@@ -558,7 +558,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
* @param message a message to be shown
*/
protected void showToast(final String message) {
mHandler.post(() -> Toast.makeText(BleProfileService.this, message, Toast.LENGTH_SHORT).show());
handler.post(() -> Toast.makeText(BleProfileService.this, message, Toast.LENGTH_SHORT).show());
}
/**
@@ -568,7 +568,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
* @return the log session
*/
protected ILogSession getLogSession() {
return mLogSession;
return logSession;
}
/**
@@ -577,7 +577,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
* @return device address
*/
protected String getDeviceAddress() {
return mBluetoothDevice.getAddress();
return bluetoothDevice.getAddress();
}
/**
@@ -586,7 +586,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
* @return bluetooth device
*/
protected BluetoothDevice getBluetoothDevice() {
return mBluetoothDevice;
return bluetoothDevice;
}
/**
@@ -595,7 +595,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
* @return the device name
*/
protected String getDeviceName() {
return mDeviceName;
return deviceName;
}
/**
@@ -604,6 +604,6 @@ public abstract class BleProfileService extends Service implements BleManagerCal
* @return <code>true</code> if device is connected to the sensor, <code>false</code> otherwise
*/
protected boolean isConnected() {
return mBleManager != null && mBleManager.isConnected();
return bleManager != null && bleManager.isConnected();
}
}

View File

@@ -79,16 +79,16 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
private static final String LOG_URI = "log_uri";
protected static final int REQUEST_ENABLE_BT = 2;
private E mService;
private E service;
private TextView mDeviceNameView;
private Button mConnectButton;
private TextView deviceNameView;
private Button connectButton;
private ILogSession mLogSession;
private BluetoothDevice mBluetoothDevice;
private String mDeviceName;
private ILogSession logSession;
private BluetoothDevice bluetoothDevice;
private String deviceName;
private final BroadcastReceiver mCommonBroadcastReceiver = new BroadcastReceiver() {
private final BroadcastReceiver commonBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
// Check if the broadcast applies the connected device
@@ -96,6 +96,9 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
return;
final BluetoothDevice bluetoothDevice = intent.getParcelableExtra(BleProfileService.EXTRA_DEVICE);
if (bluetoothDevice == null)
return;
final String action = intent.getAction();
switch (action) {
case BleProfileService.BROADCAST_CONNECTION_STATE: {
@@ -103,13 +106,13 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
switch (state) {
case BleProfileService.STATE_CONNECTED: {
mDeviceName = intent.getStringExtra(BleProfileService.EXTRA_DEVICE_NAME);
deviceName = intent.getStringExtra(BleProfileService.EXTRA_DEVICE_NAME);
onDeviceConnected(bluetoothDevice);
break;
}
case BleProfileService.STATE_DISCONNECTED: {
onDeviceDisconnected(bluetoothDevice);
mDeviceName = null;
deviceName = null;
break;
}
case BleProfileService.STATE_LINK_LOSS: {
@@ -167,28 +170,28 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
}
};
private ServiceConnection mServiceConnection = new ServiceConnection() {
private ServiceConnection serviceConnection = new ServiceConnection() {
@SuppressWarnings("unchecked")
@Override
public void onServiceConnected(final ComponentName name, final IBinder service) {
final E bleService = mService = (E) service;
mBluetoothDevice = bleService.getBluetoothDevice();
mLogSession = mService.getLogSession();
Logger.d(mLogSession, "Activity bound to the service");
final E bleService = BleProfileServiceReadyActivity.this.service = (E) service;
bluetoothDevice = bleService.getBluetoothDevice();
logSession = bleService.getLogSession();
Logger.d(logSession, "Activity bound to the service");
onServiceBound(bleService);
// Update UI
mDeviceName = bleService.getDeviceName();
mDeviceNameView.setText(mDeviceName);
mConnectButton.setText(R.string.action_disconnect);
deviceName = bleService.getDeviceName();
deviceNameView.setText(deviceName);
connectButton.setText(R.string.action_disconnect);
// And notify user if device is connected
if (bleService.isConnected()) {
onDeviceConnected(mBluetoothDevice);
onDeviceConnected(bluetoothDevice);
} else {
// If the device is not connected it means that either it is still connecting,
// or the link was lost and service is trying to connect to it (autoConnect=true).
onDeviceConnecting(mBluetoothDevice);
onDeviceConnecting(bluetoothDevice);
}
}
@@ -198,14 +201,14 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
// not when it stops itself or is stopped by the activity.
// It will be called only when there is critically low memory, in practice never
// when the activity is in foreground.
Logger.d(mLogSession, "Activity disconnected from the service");
mDeviceNameView.setText(getDefaultDeviceName());
mConnectButton.setText(R.string.action_connect);
Logger.d(logSession, "Activity disconnected from the service");
deviceNameView.setText(getDefaultDeviceName());
connectButton.setText(R.string.action_connect);
mService = null;
mDeviceName = null;
mBluetoothDevice = null;
mLogSession = null;
service = null;
deviceName = null;
bluetoothDevice = null;
logSession = null;
onServiceUnbound();
}
};
@@ -222,7 +225,7 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
// Restore the old log session
if (savedInstanceState != null) {
final Uri logUri = savedInstanceState.getParcelable(LOG_URI);
mLogSession = Logger.openSession(getApplicationContext(), logUri);
logSession = Logger.openSession(getApplicationContext(), logUri);
}
// In onInitialize method a final class may register local broadcast receivers that will listen for events from the service
@@ -238,7 +241,7 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
// View is ready to be used
onViewCreated(savedInstanceState);
LocalBroadcastManager.getInstance(this).registerReceiver(mCommonBroadcastReceiver, makeIntentFilter());
LocalBroadcastManager.getInstance(this).registerReceiver(commonBroadcastReceiver, makeIntentFilter());
}
@Override
@@ -247,16 +250,16 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
/*
* If the service has not been started before, the following lines will not start it.
* However, if it's running, the Activity will bind to it and notified via mServiceConnection.
* However, if it's running, the Activity will bind to it and notified via serviceConnection.
*/
final Intent service = new Intent(this, getServiceClass());
// We pass 0 as a flag so the service will not be created if not exists.
bindService(service, mServiceConnection, 0);
bindService(service, serviceConnection, 0);
/*
* When user exited the UARTActivity while being connected, the log session is kept in
* the service. We may not get it before binding to it so in this case this event will
* not be logged (mLogSession is null until onServiceConnected(..) is called).
* not be logged (logSession is null until onServiceConnected(..) is called).
* It will, however, be logged after the orientation changes.
*/
}
@@ -270,17 +273,17 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
// in the service if we are just rotating the screen. However, when the activity will
// disappear, we may want to disable some device features to reduce the battery
// consumption.
if (mService != null)
mService.setActivityIsChangingConfiguration(isChangingConfigurations());
if (service != null)
service.setActivityIsChangingConfiguration(isChangingConfigurations());
unbindService(mServiceConnection);
mService = null;
unbindService(serviceConnection);
service = null;
Logger.d(mLogSession, "Activity unbound from the service");
Logger.d(logSession, "Activity unbound from the service");
onServiceUnbound();
mDeviceName = null;
mBluetoothDevice = null;
mLogSession = null;
deviceName = null;
bluetoothDevice = null;
logSession = null;
} catch (final IllegalArgumentException e) {
// do nothing, we were not connected to the sensor
}
@@ -290,7 +293,7 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
protected void onDestroy() {
super.onDestroy();
LocalBroadcastManager.getInstance(this).unregisterReceiver(mCommonBroadcastReceiver);
LocalBroadcastManager.getInstance(this).unregisterReceiver(commonBroadcastReceiver);
}
private static IntentFilter makeIntentFilter() {
@@ -329,7 +332,7 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
* @return the service binder or <code>null</code>
*/
protected E getService() {
return mService;
return service;
}
/**
@@ -364,24 +367,24 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
protected final void setUpView() {
// set GUI
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
mConnectButton = findViewById(R.id.action_connect);
mDeviceNameView = findViewById(R.id.device_name);
connectButton = findViewById(R.id.action_connect);
deviceNameView = findViewById(R.id.device_name);
}
@Override
protected void onSaveInstanceState(final Bundle outState) {
protected void onSaveInstanceState(@NonNull final Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(SIS_DEVICE_NAME, mDeviceName);
outState.putParcelable(SIS_DEVICE, mBluetoothDevice);
if (mLogSession != null)
outState.putParcelable(LOG_URI, mLogSession.getSessionUri());
outState.putString(SIS_DEVICE_NAME, deviceName);
outState.putParcelable(SIS_DEVICE, bluetoothDevice);
if (logSession != null)
outState.putParcelable(LOG_URI, logSession.getSessionUri());
}
@Override
protected void onRestoreInstanceState(final @NonNull Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mDeviceName = savedInstanceState.getString(SIS_DEVICE_NAME);
mBluetoothDevice = savedInstanceState.getParcelable(SIS_DEVICE);
deviceName = savedInstanceState.getString(SIS_DEVICE_NAME);
bluetoothDevice = savedInstanceState.getParcelable(SIS_DEVICE);
}
@Override
@@ -423,11 +426,11 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
*/
public void onConnectClicked(final View view) {
if (isBLEEnabled()) {
if (mService == null) {
if (service == null) {
setDefaultUI();
showDeviceScanningDialog(getFilterUUID());
} else {
mService.disconnect();
service.disconnect();
}
} else {
showBLEDialog();
@@ -453,28 +456,28 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
}
@Override
public void onDeviceSelected(final BluetoothDevice device, final String name) {
public void onDeviceSelected(@NonNull final BluetoothDevice device, final String name) {
final int titleId = getLoggerProfileTitle();
if (titleId > 0) {
mLogSession = Logger.newSession(getApplicationContext(), getString(titleId), device.getAddress(), name);
logSession = Logger.newSession(getApplicationContext(), getString(titleId), device.getAddress(), name);
// If nRF Logger is not installed we may want to use local logger
if (mLogSession == null && getLocalAuthorityLogger() != null) {
mLogSession = LocalLogSession.newSession(getApplicationContext(), getLocalAuthorityLogger(), device.getAddress(), name);
if (logSession == null && getLocalAuthorityLogger() != null) {
logSession = LocalLogSession.newSession(getApplicationContext(), getLocalAuthorityLogger(), device.getAddress(), name);
}
}
mBluetoothDevice = device;
mDeviceName = name;
bluetoothDevice = device;
deviceName = name;
// The device may not be in the range but the service will try to connect to it if it reach it
Logger.d(mLogSession, "Creating service...");
Logger.d(logSession, "Creating service...");
final Intent service = new Intent(this, getServiceClass());
service.putExtra(BleProfileService.EXTRA_DEVICE_ADDRESS, device.getAddress());
service.putExtra(BleProfileService.EXTRA_DEVICE_NAME, name);
if (mLogSession != null)
service.putExtra(BleProfileService.EXTRA_LOG_URI, mLogSession.getSessionUri());
if (logSession != null)
service.putExtra(BleProfileService.EXTRA_LOG_URI, logSession.getSessionUri());
startService(service);
Logger.d(mLogSession, "Binding to the service...");
bindService(service, mServiceConnection, 0);
Logger.d(logSession, "Binding to the service...");
bindService(service, serviceConnection, 0);
}
@Override
@@ -483,80 +486,80 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
}
@Override
public void onDeviceConnecting(final BluetoothDevice device) {
mDeviceNameView.setText(mDeviceName != null ? mDeviceName : getString(R.string.not_available));
mConnectButton.setText(R.string.action_connecting);
public void onDeviceConnecting(@NonNull final BluetoothDevice device) {
deviceNameView.setText(deviceName != null ? deviceName : getString(R.string.not_available));
connectButton.setText(R.string.action_connecting);
}
@Override
public void onDeviceConnected(final BluetoothDevice device) {
mDeviceNameView.setText(mDeviceName);
mConnectButton.setText(R.string.action_disconnect);
public void onDeviceConnected(@NonNull final BluetoothDevice device) {
deviceNameView.setText(deviceName);
connectButton.setText(R.string.action_disconnect);
}
@Override
public void onDeviceDisconnecting(final BluetoothDevice device) {
mConnectButton.setText(R.string.action_disconnecting);
public void onDeviceDisconnecting(@NonNull final BluetoothDevice device) {
connectButton.setText(R.string.action_disconnecting);
}
@Override
public void onDeviceDisconnected(final BluetoothDevice device) {
mConnectButton.setText(R.string.action_connect);
mDeviceNameView.setText(getDefaultDeviceName());
public void onDeviceDisconnected(@NonNull final BluetoothDevice device) {
connectButton.setText(R.string.action_connect);
deviceNameView.setText(getDefaultDeviceName());
try {
Logger.d(mLogSession, "Unbinding from the service...");
unbindService(mServiceConnection);
mService = null;
Logger.d(logSession, "Unbinding from the service...");
unbindService(serviceConnection);
service = null;
Logger.d(mLogSession, "Activity unbound from the service");
Logger.d(logSession, "Activity unbound from the service");
onServiceUnbound();
mDeviceName = null;
mBluetoothDevice = null;
mLogSession = null;
deviceName = null;
bluetoothDevice = null;
logSession = null;
} catch (final IllegalArgumentException e) {
// do nothing. This should never happen but does...
}
}
@Override
public void onLinkLossOccurred(final BluetoothDevice device) {
public void onLinkLossOccurred(@NonNull final BluetoothDevice device) {
// empty default implementation
}
@Override
public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) {
public void onServicesDiscovered(@NonNull final BluetoothDevice device, final boolean optionalServicesFound) {
// empty default implementation
}
@Override
public void onDeviceReady(final BluetoothDevice device) {
public void onDeviceReady(@NonNull final BluetoothDevice device) {
// empty default implementation
}
@Override
public void onBondingRequired(final BluetoothDevice device) {
public void onBondingRequired(@NonNull final BluetoothDevice device) {
// empty default implementation
}
@Override
public void onBonded(final BluetoothDevice device) {
public void onBonded(@NonNull final BluetoothDevice device) {
// empty default implementation
}
@Override
public void onBondingFailed(final BluetoothDevice device) {
public void onBondingFailed(@NonNull final BluetoothDevice device) {
// empty default implementation
}
@Override
public void onError(final BluetoothDevice device, final String message, final int errorCode) {
public void onError(@NonNull final BluetoothDevice device, @NonNull final String message, final int errorCode) {
DebugLogger.e(TAG, "Error occurred: " + message + ", error code: " + errorCode);
showToast(message + " (" + errorCode + ")");
}
@Override
public void onDeviceNotSupported(final BluetoothDevice device) {
public void onDeviceNotSupported(@NonNull final BluetoothDevice device) {
showToast(R.string.not_supported);
}
@@ -582,14 +585,14 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
* Returns <code>true</code> if the device is connected. Services may not have been discovered yet.
*/
protected boolean isDeviceConnected() {
return mService != null && mService.isConnected();
return service != null && service.isConnected();
}
/**
* Returns the name of the device that the phone is currently connected to or was connected last time
*/
protected String getDeviceName() {
return mDeviceName;
return deviceName;
}
/**
@@ -627,7 +630,7 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
*/
protected boolean isBroadcastForThisDevice(final Intent intent) {
final BluetoothDevice bluetoothDevice = intent.getParcelableExtra(BleProfileService.EXTRA_DEVICE);
return mBluetoothDevice != null && mBluetoothDevice.equals(bluetoothDevice);
return bluetoothDevice != null && bluetoothDevice.equals(bluetoothDevice);
}
/**
@@ -648,7 +651,7 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
* @return the logger session or <code>null</code>
*/
protected ILogSession getLogSession() {
return mLogSession;
return logSession;
}
private void ensureBLESupported() {
@@ -659,8 +662,7 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
}
protected boolean isBLEEnabled() {
final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
final BluetoothAdapter adapter = bluetoothManager.getAdapter();
final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
return adapter != null && adapter.isEnabled();
}

View File

@@ -17,13 +17,13 @@ import no.nordicsemi.android.log.Logger;
* @param <T> the callbacks class.
*/
public abstract class LoggableBleManager<T extends BleManagerCallbacks> extends BleManager<T> {
private ILogSession mLogSession;
private ILogSession logSession;
/**
* The manager constructor.
* <p>
* After constructing the manager, the callbacks object must be set with
* {@link #setGattCallbacks(BleManagerCallbacks)}.
* {@link #setManagerCallbacks(BleManagerCallbacks)}.
*
* @param context the context.
*/
@@ -37,12 +37,12 @@ public abstract class LoggableBleManager<T extends BleManagerCallbacks> extends
* @param session nRF Logger log session to log inti, or null, if nRF Logger is not installed.
*/
public void setLogger(@Nullable final ILogSession session) {
mLogSession = session;
logSession = session;
}
@Override
public void log(final int priority, @NonNull final String message) {
Logger.log(mLogSession, LogContract.Log.Level.fromPriority(priority), message);
Logger.log(logSession, LogContract.Log.Level.fromPriority(priority), message);
Log.println(priority, "BleManager", message);
}
}

View File

@@ -77,14 +77,14 @@ public abstract class BleMulticonnectProfileService extends Service implements B
public static final int STATE_CONNECTING = 2;
public static final int STATE_DISCONNECTING = 3;
private HashMap<BluetoothDevice, LoggableBleManager<BleManagerCallbacks>> mBleManagers;
private List<BluetoothDevice> mManagedDevices;
private Handler mHandler;
private HashMap<BluetoothDevice, LoggableBleManager<BleManagerCallbacks>> bleManagers;
private List<BluetoothDevice> managedDevices;
private Handler handler;
protected boolean mBound;
private boolean mActivityIsChangingConfiguration;
protected boolean bound;
private boolean activityIsChangingConfiguration;
private final BroadcastReceiver mBluetoothStateBroadcastReceiver = new BroadcastReceiver() {
private final BroadcastReceiver bluetoothStateBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF);
@@ -95,7 +95,7 @@ public abstract class BleMulticonnectProfileService extends Service implements B
// On older phones (tested on Nexus 4 with Android 5.0.1) the Bluetooth requires some time
// after it has been enabled before some operations can start. Starting the GATT server here
// without a delay is very likely to cause a DeadObjectException from BluetoothManager#openGattServer(...).
mHandler.postDelayed(() -> onBluetoothEnabled(), 600);
handler.postDelayed(() -> onBluetoothEnabled(), 600);
break;
case BluetoothAdapter.STATE_TURNING_OFF:
case BluetoothAdapter.STATE_OFF:
@@ -114,7 +114,7 @@ public abstract class BleMulticonnectProfileService extends Service implements B
* @return unmodifiable list of devices managed by the service
*/
public final List<BluetoothDevice> getManagedDevices() {
return Collections.unmodifiableList(mManagedDevices);
return Collections.unmodifiableList(managedDevices);
}
/**
@@ -134,26 +134,25 @@ public abstract class BleMulticonnectProfileService extends Service implements B
public void connect(final BluetoothDevice device, final ILogSession session) {
// If a device is in managed devices it means that it's already connected, or was connected
// using autoConnect and the link was lost but Android is already trying to connect to it.
if (mManagedDevices.contains(device))
if (managedDevices.contains(device))
return;
mManagedDevices.add(device);
managedDevices.add(device);
LoggableBleManager<BleManagerCallbacks> manager = mBleManagers.get(device);
if (manager != null) {
if (session != null)
manager.setLogger(session);
manager.connect(device).enqueue();
} else {
mBleManagers.put(device, manager = initializeManager());
manager.setGattCallbacks(BleMulticonnectProfileService.this);
manager.setLogger(session);
manager.connect(device)
.fail((d, status) -> {
mManagedDevices.remove(device);
mBleManagers.remove(device);
})
.enqueue(10000);
LoggableBleManager<BleManagerCallbacks> manager = bleManagers.get(device);
if (manager == null) {
bleManagers.put(device, manager = initializeManager());
manager.setManagerCallbacks(BleMulticonnectProfileService.this);
}
manager.setLogger(session);
manager.connect(device)
.retry(2, 100)
.useAutoConnect(shouldAutoConnect())
.timeout(10000)
.fail((d, status) -> {
managedDevices.remove(device);
bleManagers.remove(device);
})
.enqueue();
}
/**
@@ -163,11 +162,11 @@ public abstract class BleMulticonnectProfileService extends Service implements B
* @param device target device to disconnect and forget
*/
public void disconnect(final BluetoothDevice device) {
final BleManager<BleManagerCallbacks> manager = mBleManagers.get(device);
final BleManager<BleManagerCallbacks> manager = bleManagers.get(device);
if (manager != null && manager.isConnected()) {
manager.disconnect().enqueue();
}
mManagedDevices.remove(device);
managedDevices.remove(device);
}
/**
@@ -176,7 +175,7 @@ public abstract class BleMulticonnectProfileService extends Service implements B
* @return <code>true</code> if device is connected to the sensor, <code>false</code> otherwise
*/
public final boolean isConnected(final BluetoothDevice device) {
final BleManager<BleManagerCallbacks> manager = mBleManagers.get(device);
final BleManager<BleManagerCallbacks> manager = bleManagers.get(device);
return manager != null && manager.isConnected();
}
@@ -187,7 +186,7 @@ public abstract class BleMulticonnectProfileService extends Service implements B
* initializing. False otherwise.
*/
public final boolean isReady(final BluetoothDevice device) {
final BleManager<BleManagerCallbacks> manager = mBleManagers.get(device);
final BleManager<BleManagerCallbacks> manager = bleManagers.get(device);
return manager != null && manager.isReady();
}
@@ -196,8 +195,9 @@ public abstract class BleMulticonnectProfileService extends Service implements B
* @param device the target device
* @return the connection state, as in {@link BleManager#getConnectionState()}.
*/
@SuppressWarnings("unused")
public final int getConnectionState(final BluetoothDevice device) {
final BleManager<BleManagerCallbacks> manager = mBleManagers.get(device);
final BleManager<BleManagerCallbacks> manager = bleManagers.get(device);
return manager != null ? manager.getConnectionState() : BluetoothGatt.STATE_DISCONNECTED;
}
@@ -207,10 +207,13 @@ public abstract class BleMulticonnectProfileService extends Service implements B
* @return battery value or -1 if no value was received or Battery Level characteristic was not found
* @deprecated Keep battery value in your manager instead.
*/
@SuppressWarnings("deprecation")
@Deprecated
public int getBatteryValue(final BluetoothDevice device) {
final BleManager<BleManagerCallbacks> manager = mBleManagers.get(device);
return manager.getBatteryValue();
final BleManager<BleManagerCallbacks> manager = bleManagers.get(device);
if (manager != null)
return manager.getBatteryValue();
return 0;
}
/**
@@ -218,33 +221,34 @@ public abstract class BleMulticonnectProfileService extends Service implements B
* If <code>false</code>, we will turn off battery level notifications in onUnbind(..) method below.
* @param changing true if the bound activity is finishing
*/
@SuppressWarnings("WeakerAccess")
public final void setActivityIsChangingConfiguration(final boolean changing) {
mActivityIsChangingConfiguration = changing;
activityIsChangingConfiguration = changing;
}
@Override
public void log(final BluetoothDevice device, final int level, final String message) {
final BleManager<BleManagerCallbacks> manager = mBleManagers.get(device);
public void log(@NonNull final BluetoothDevice device, final int level, final String message) {
final BleManager<BleManagerCallbacks> manager = bleManagers.get(device);
if (manager != null)
manager.log(level, message);
}
@Override
public void log(final BluetoothDevice device, final int level, @StringRes final int messageRes, final Object... params) {
final BleManager<BleManagerCallbacks> manager = mBleManagers.get(device);
public void log(@NonNull final BluetoothDevice device, final int level, @StringRes final int messageRes, final Object... params) {
final BleManager<BleManagerCallbacks> manager = bleManagers.get(device);
if (manager != null)
manager.log(level, messageRes, params);
}
@Override
public void log(final int level, @NonNull final String message) {
for (final BleManager<BleManagerCallbacks> manager : mBleManagers.values())
for (final BleManager<BleManagerCallbacks> manager : bleManagers.values())
manager.log(level, message);
}
@Override
public void log(final int level, @StringRes final int messageRes, final Object... params) {
for (final BleManager<BleManagerCallbacks> manager : mBleManagers.values())
for (final BleManager<BleManagerCallbacks> manager : bleManagers.values())
manager.log(level, messageRes, params);
}
}
@@ -254,7 +258,16 @@ public abstract class BleMulticonnectProfileService extends Service implements B
* The handler may be used to postpone execution of some operations or to run them in UI thread.
*/
protected Handler getHandler() {
return mHandler;
return handler;
}
/**
* This method returns whether autoConnect option should be used.
*
* @return true to use autoConnect feature, false (default) otherwise.
*/
protected boolean shouldAutoConnect() {
return false;
}
/**
@@ -269,15 +282,15 @@ public abstract class BleMulticonnectProfileService extends Service implements B
@Override
public IBinder onBind(final Intent intent) {
mBound = true;
bound = true;
return getBinder();
}
@Override
public final void onRebind(final Intent intent) {
mBound = true;
bound = true;
if (!mActivityIsChangingConfiguration) {
if (!activityIsChangingConfiguration) {
onRebind();
}
}
@@ -293,10 +306,10 @@ public abstract class BleMulticonnectProfileService extends Service implements B
@Override
public final boolean onUnbind(final Intent intent) {
mBound = false;
bound = false;
if (!mActivityIsChangingConfiguration) {
if (!mManagedDevices.isEmpty()) {
if (!activityIsChangingConfiguration) {
if (!managedDevices.isEmpty()) {
onUnbind();
} else {
// The last activity has disconnected from the service and there are no devices to manage. The service may be stopped.
@@ -320,14 +333,14 @@ public abstract class BleMulticonnectProfileService extends Service implements B
public void onCreate() {
super.onCreate();
mHandler = new Handler();
handler = new Handler();
// Initialize the map of BLE managers
mBleManagers = new HashMap<>();
mManagedDevices = new ArrayList<>();
bleManagers = new HashMap<>();
managedDevices = new ArrayList<>();
// Register broadcast receivers
registerReceiver(mBluetoothStateBroadcastReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
registerReceiver(bluetoothStateBroadcastReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
// Service has now been created
onServiceCreated();
@@ -381,7 +394,7 @@ public abstract class BleMulticonnectProfileService extends Service implements B
public void onDestroy() {
super.onDestroy();
onServiceStopped();
mHandler = null;
handler = null;
}
/**
@@ -389,18 +402,18 @@ public abstract class BleMulticonnectProfileService extends Service implements B
*/
protected void onServiceStopped() {
// Unregister broadcast receivers
unregisterReceiver(mBluetoothStateBroadcastReceiver);
unregisterReceiver(bluetoothStateBroadcastReceiver);
// The managers map may not be empty if the service was killed by the system
for (final BleManager<BleManagerCallbacks> manager : mBleManagers.values()) {
for (final BleManager<BleManagerCallbacks> manager : bleManagers.values()) {
// Service is being destroyed, no need to disconnect manually.
manager.close();
manager.log(Log.INFO, "Service destroyed");
}
mBleManagers.clear();
mManagedDevices.clear();
mBleManagers = null;
mManagedDevices = null;
bleManagers.clear();
managedDevices.clear();
bleManagers = null;
managedDevices = null;
}
/**
@@ -418,15 +431,15 @@ public abstract class BleMulticonnectProfileService extends Service implements B
* devices that were connected before the Bluetooth was turned off.
*/
protected void onBluetoothEnabled() {
for (final BluetoothDevice device : mManagedDevices) {
final BleManager<BleManagerCallbacks> manager = mBleManagers.get(device);
if (!manager.isConnected())
for (final BluetoothDevice device : managedDevices) {
final BleManager<BleManagerCallbacks> manager = bleManagers.get(device);
if (manager != null && !manager.isConnected())
manager.connect(device).enqueue();
}
}
@Override
public void onDeviceConnecting(final BluetoothDevice device) {
public void onDeviceConnecting(@NonNull final BluetoothDevice device) {
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
broadcast.putExtra(EXTRA_DEVICE, device);
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_CONNECTING);
@@ -434,7 +447,7 @@ public abstract class BleMulticonnectProfileService extends Service implements B
}
@Override
public void onDeviceConnected(final BluetoothDevice device) {
public void onDeviceConnected(@NonNull final BluetoothDevice device) {
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
broadcast.putExtra(EXTRA_DEVICE, device);
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_CONNECTED);
@@ -442,7 +455,7 @@ public abstract class BleMulticonnectProfileService extends Service implements B
}
@Override
public void onDeviceDisconnecting(final BluetoothDevice device) {
public void onDeviceDisconnecting(@NonNull final BluetoothDevice device) {
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
broadcast.putExtra(EXTRA_DEVICE, device);
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_DISCONNECTING);
@@ -450,15 +463,15 @@ public abstract class BleMulticonnectProfileService extends Service implements B
}
@Override
public void onDeviceDisconnected(final BluetoothDevice device) {
public void onDeviceDisconnected(@NonNull final BluetoothDevice device) {
// Note: if BleManager#shouldAutoConnect() for this device returned true, this callback will be
// invoked ONLY when user requested disconnection (using Disconnect button). If the device
// disconnects due to a link loss, the onLinkLossOccurred(BluetoothDevice) method will be called instead.
// We no longer want to keep the device in the service
mManagedDevices.remove(device);
managedDevices.remove(device);
// The BleManager is not removed from the HashMap in order to keep the device's log session.
// mBleManagers.remove(device);
// bleManagers.remove(device);
// Do not use the device argument here unless you change calling onDeviceDisconnected from the binder above
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
@@ -467,13 +480,13 @@ public abstract class BleMulticonnectProfileService extends Service implements B
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
// When user disconnected the last device while the activity was not bound the service can be stopped
if (!mBound && mManagedDevices.isEmpty()) {
if (!bound && managedDevices.isEmpty()) {
stopSelf();
}
}
@Override
public void onLinkLossOccurred(final BluetoothDevice device) {
public void onLinkLossOccurred(@NonNull final BluetoothDevice device) {
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
broadcast.putExtra(EXTRA_DEVICE, device);
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_LINK_LOSS);
@@ -481,7 +494,7 @@ public abstract class BleMulticonnectProfileService extends Service implements B
}
@Override
public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) {
public void onServicesDiscovered(@NonNull final BluetoothDevice device, final boolean optionalServicesFound) {
final Intent broadcast = new Intent(BROADCAST_SERVICES_DISCOVERED);
broadcast.putExtra(EXTRA_DEVICE, device);
broadcast.putExtra(EXTRA_SERVICE_PRIMARY, true);
@@ -490,17 +503,17 @@ public abstract class BleMulticonnectProfileService extends Service implements B
}
@Override
public void onDeviceReady(final BluetoothDevice device) {
public void onDeviceReady(@NonNull final BluetoothDevice device) {
final Intent broadcast = new Intent(BROADCAST_DEVICE_READY);
broadcast.putExtra(EXTRA_DEVICE, device);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
}
@Override
public void onDeviceNotSupported(final BluetoothDevice device) {
public void onDeviceNotSupported(@NonNull final BluetoothDevice device) {
// We don't like this device, remove it from both collections
mManagedDevices.remove(device);
mBleManagers.remove(device);
managedDevices.remove(device);
bleManagers.remove(device);
final Intent broadcast = new Intent(BROADCAST_SERVICES_DISCOVERED);
broadcast.putExtra(EXTRA_DEVICE, device);
@@ -511,8 +524,9 @@ public abstract class BleMulticonnectProfileService extends Service implements B
// no need for disconnecting, it will be disconnected by the manager automatically
}
@SuppressWarnings("deprecation")
@Override
public void onBatteryValueReceived(final BluetoothDevice device, final int value) {
public void onBatteryValueReceived(@NonNull final BluetoothDevice device, final int value) {
final Intent broadcast = new Intent(BROADCAST_BATTERY_LEVEL);
broadcast.putExtra(EXTRA_DEVICE, device);
broadcast.putExtra(EXTRA_BATTERY_LEVEL, value);
@@ -520,7 +534,7 @@ public abstract class BleMulticonnectProfileService extends Service implements B
}
@Override
public void onBondingRequired(final BluetoothDevice device) {
public void onBondingRequired(@NonNull final BluetoothDevice device) {
showToast(no.nordicsemi.android.nrftoolbox.common.R.string.bonding);
final Intent broadcast = new Intent(BROADCAST_BOND_STATE);
@@ -530,7 +544,7 @@ public abstract class BleMulticonnectProfileService extends Service implements B
}
@Override
public void onBonded(final BluetoothDevice device) {
public void onBonded(@NonNull final BluetoothDevice device) {
showToast(no.nordicsemi.android.nrftoolbox.common.R.string.bonded);
final Intent broadcast = new Intent(BROADCAST_BOND_STATE);
@@ -540,7 +554,7 @@ public abstract class BleMulticonnectProfileService extends Service implements B
}
@Override
public void onBondingFailed(final BluetoothDevice device) {
public void onBondingFailed(@NonNull final BluetoothDevice device) {
showToast(no.nordicsemi.android.nrftoolbox.common.R.string.bonding_failed);
final Intent broadcast = new Intent(BROADCAST_BOND_STATE);
@@ -550,7 +564,7 @@ public abstract class BleMulticonnectProfileService extends Service implements B
}
@Override
public void onError(final BluetoothDevice device, final String message, final int errorCode) {
public void onError(@NonNull final BluetoothDevice device, @NonNull final String message, final int errorCode) {
final Intent broadcast = new Intent(BROADCAST_ERROR);
broadcast.putExtra(EXTRA_DEVICE, device);
broadcast.putExtra(EXTRA_ERROR_MESSAGE, message);
@@ -565,7 +579,7 @@ public abstract class BleMulticonnectProfileService extends Service implements B
* an resource id of the message to be shown
*/
protected void showToast(final int messageResId) {
mHandler.post(() -> Toast.makeText(BleMulticonnectProfileService.this, messageResId, Toast.LENGTH_SHORT).show());
handler.post(() -> Toast.makeText(BleMulticonnectProfileService.this, messageResId, Toast.LENGTH_SHORT).show());
}
/**
@@ -575,7 +589,7 @@ public abstract class BleMulticonnectProfileService extends Service implements B
* a message to be shown
*/
protected void showToast(final String message) {
mHandler.post(() -> Toast.makeText(BleMulticonnectProfileService.this, message, Toast.LENGTH_SHORT).show());
handler.post(() -> Toast.makeText(BleMulticonnectProfileService.this, message, Toast.LENGTH_SHORT).show());
}
/**
@@ -585,7 +599,7 @@ public abstract class BleMulticonnectProfileService extends Service implements B
* @return the BleManager or null
*/
protected BleManager<? extends BleManagerCallbacks> getBleManager(final BluetoothDevice device) {
return mBleManagers.get(device);
return bleManagers.get(device);
}
/**
@@ -593,7 +607,7 @@ public abstract class BleMulticonnectProfileService extends Service implements B
* @return list of managed devices
*/
protected List<BluetoothDevice> getManagedDevices() {
return Collections.unmodifiableList(mManagedDevices);
return Collections.unmodifiableList(managedDevices);
}
/**
@@ -602,8 +616,9 @@ public abstract class BleMulticonnectProfileService extends Service implements B
*/
protected List<BluetoothDevice> getConnectedDevices() {
final List<BluetoothDevice> list = new ArrayList<>();
for (BluetoothDevice device : mManagedDevices) {
if (mBleManagers.get(device).isConnected())
for (BluetoothDevice device : managedDevices) {
final BleManager<BleManagerCallbacks> manager = bleManagers.get(device);
if (manager != null && manager.isConnected())
list.add(device);
}
return Collections.unmodifiableList(list);
@@ -615,7 +630,7 @@ public abstract class BleMulticonnectProfileService extends Service implements B
* @return <code>true</code> if device is connected to the sensor, <code>false</code> otherwise
*/
protected boolean isConnected(final BluetoothDevice device) {
final BleManager<BleManagerCallbacks> manager = mBleManagers.get(device);
final BleManager<BleManagerCallbacks> manager = bleManagers.get(device);
return manager != null && manager.isConnected();
}
}

View File

@@ -24,7 +24,6 @@ package no.nordicsemi.android.nrftoolbox.profile.multiconnect;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -35,9 +34,6 @@ import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
@@ -49,6 +45,10 @@ import java.util.Collections;
import java.util.List;
import java.util.UUID;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import no.nordicsemi.android.ble.BleManagerCallbacks;
import no.nordicsemi.android.log.ILogSession;
import no.nordicsemi.android.log.LocalLogSession;
@@ -71,19 +71,24 @@ import no.nordicsemi.android.nrftoolbox.utility.DebugLogger;
* listens for updates from them. When entering back to the activity, activity will to bind to the service and refresh UI.
* </p>
*/
@SuppressWarnings("unused")
public abstract class BleMulticonnectProfileServiceReadyActivity<E extends BleMulticonnectProfileService.LocalBinder> extends AppCompatActivity implements
ScannerFragment.OnDeviceSelectedListener, BleManagerCallbacks {
private static final String TAG = "BleMulticonnectProfileServiceReadyActivity";
protected static final int REQUEST_ENABLE_BT = 2;
private E mService;
private List<BluetoothDevice> mManagedDevices;
private E service;
private List<BluetoothDevice> managedDevices;
private final BroadcastReceiver mCommonBroadcastReceiver = new BroadcastReceiver() {
private final BroadcastReceiver commonBroadcastReceiver = new BroadcastReceiver() {
@SuppressWarnings("deprecation")
@Override
public void onReceive(final Context context, final Intent intent) {
final BluetoothDevice bluetoothDevice = intent.getParcelableExtra(BleMulticonnectProfileService.EXTRA_DEVICE);
if (bluetoothDevice == null)
return;
final String action = intent.getAction();
switch (action) {
case BleMulticonnectProfileService.BROADCAST_CONNECTION_STATE: {
@@ -159,17 +164,17 @@ public abstract class BleMulticonnectProfileServiceReadyActivity<E extends BleMu
}
};
private ServiceConnection mServiceConnection = new ServiceConnection() {
private ServiceConnection serviceConnection = new ServiceConnection() {
@SuppressWarnings("unchecked")
@Override
public void onServiceConnected(final ComponentName name, final IBinder service) {
final E bleService = mService = (E) service;
final E bleService = BleMulticonnectProfileServiceReadyActivity.this.service = (E) service;
bleService.log(Log.DEBUG, "Activity bound to the service");
mManagedDevices.addAll(bleService.getManagedDevices());
managedDevices.addAll(bleService.getManagedDevices());
onServiceBound(bleService);
// and notify user if device is connected
for (final BluetoothDevice device : mManagedDevices) {
for (final BluetoothDevice device : managedDevices) {
if (bleService.isConnected(device))
onDeviceConnected(device);
}
@@ -177,7 +182,7 @@ public abstract class BleMulticonnectProfileServiceReadyActivity<E extends BleMu
@Override
public void onServiceDisconnected(final ComponentName name) {
mService = null;
service = null;
onServiceUnbound();
}
};
@@ -185,7 +190,7 @@ public abstract class BleMulticonnectProfileServiceReadyActivity<E extends BleMu
@Override
protected final void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mManagedDevices = new ArrayList<>();
managedDevices = new ArrayList<>();
ensureBLESupported();
if (!isBLEEnabled()) {
@@ -205,7 +210,7 @@ public abstract class BleMulticonnectProfileServiceReadyActivity<E extends BleMu
// View is ready to be used
onViewCreated(savedInstanceState);
LocalBroadcastManager.getInstance(this).registerReceiver(mCommonBroadcastReceiver, makeIntentFilter());
LocalBroadcastManager.getInstance(this).registerReceiver(commonBroadcastReceiver, makeIntentFilter());
}
@Override
@@ -214,29 +219,29 @@ public abstract class BleMulticonnectProfileServiceReadyActivity<E extends BleMu
/*
* In comparison to BleProfileServiceReadyActivity this activity always starts the service when started.
* Connecting to a device is done by calling mService.connect(BluetoothDevice) method, not startService(...) like there.
* Connecting to a device is done by calling service.connect(BluetoothDevice) method, not startService(...) like there.
* The service will stop itself when all devices it manages were disconnected and unmanaged and the last activity unbinds from it.
*/
final Intent service = new Intent(this, getServiceClass());
startService(service);
bindService(service, mServiceConnection, 0);
bindService(service, serviceConnection, 0);
}
@Override
protected void onStop() {
super.onStop();
if (mService != null) {
if (service != null) {
// We don't want to perform some operations (e.g. disable Battery Level notifications) in the service if we are just rotating the screen.
// However, when the activity will disappear, we may want to disable some device features to reduce the battery consumption.
mService.setActivityIsChangingConfiguration(isChangingConfigurations());
service.setActivityIsChangingConfiguration(isChangingConfigurations());
// Log it here as there is no callback when the service gets unbound
// and the mService will not be available later (the activity doesn't keep log sessions)
mService.log(Log.DEBUG, "Activity unbound from the service");
// and the service will not be available later (the activity doesn't keep log sessions)
service.log(Log.DEBUG, "Activity unbound from the service");
}
unbindService(mServiceConnection);
mService = null;
unbindService(serviceConnection);
service = null;
onServiceUnbound();
}
@@ -245,7 +250,7 @@ public abstract class BleMulticonnectProfileServiceReadyActivity<E extends BleMu
protected void onDestroy() {
super.onDestroy();
LocalBroadcastManager.getInstance(this).unregisterReceiver(mCommonBroadcastReceiver);
LocalBroadcastManager.getInstance(this).unregisterReceiver(commonBroadcastReceiver);
}
private static IntentFilter makeIntentFilter() {
@@ -284,7 +289,7 @@ public abstract class BleMulticonnectProfileServiceReadyActivity<E extends BleMu
* @return the service binder or <code>null</code>
*/
protected E getService() {
return mService;
return service;
}
/**
@@ -309,7 +314,7 @@ public abstract class BleMulticonnectProfileServiceReadyActivity<E extends BleMu
* @param savedInstanceState contains the data it most recently supplied in {@link #onSaveInstanceState(Bundle)}.
* Note: <b>Otherwise it is null</b>.
*/
protected void onViewCreated(final Bundle savedInstanceState) {
protected void onViewCreated(@SuppressWarnings("unused") final Bundle savedInstanceState) {
// empty default implementation
}
@@ -333,7 +338,7 @@ public abstract class BleMulticonnectProfileServiceReadyActivity<E extends BleMu
* @param itemId the menu item id
* @return <code>true</code> if action has been handled
*/
protected boolean onOptionsItemSelected(final int itemId) {
protected boolean onOptionsItemSelected(@SuppressWarnings("unused") final int itemId) {
// Overwrite when using menu other than R.menu.help
return false;
}
@@ -385,7 +390,7 @@ public abstract class BleMulticonnectProfileServiceReadyActivity<E extends BleMu
}
@Override
public void onDeviceSelected(final BluetoothDevice device, final String name) {
public void onDeviceSelected(@NonNull final BluetoothDevice device, final String name) {
final int titleId = getLoggerProfileTitle();
ILogSession logSession = null;
if (titleId > 0) {
@@ -396,7 +401,7 @@ public abstract class BleMulticonnectProfileServiceReadyActivity<E extends BleMu
}
}
mService.connect(device, logSession);
service.connect(device, logSession);
}
@Override
@@ -405,64 +410,66 @@ public abstract class BleMulticonnectProfileServiceReadyActivity<E extends BleMu
}
@Override
public void onDeviceConnecting(final BluetoothDevice device) {
public void onDeviceConnecting(@NonNull final BluetoothDevice device) {
// empty default implementation
}
@Override
public void onDeviceDisconnecting(final BluetoothDevice device) {
public void onDeviceDisconnecting(@NonNull final BluetoothDevice device) {
// empty default implementation
}
@Override
public void onLinkLossOccurred(final BluetoothDevice device) {
public void onLinkLossOccurred(@NonNull final BluetoothDevice device) {
// empty default implementation
}
@Override
public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) {
public void onServicesDiscovered(@NonNull final BluetoothDevice device, final boolean optionalServicesFound) {
// empty default implementation
}
@Override
public void onDeviceReady(final BluetoothDevice device) {
public void onDeviceReady(@NonNull final BluetoothDevice device) {
// empty default implementation
}
@Override
public void onBondingRequired(final BluetoothDevice device) {
public void onBondingRequired(@NonNull final BluetoothDevice device) {
// empty default implementation
}
@Override
public void onBonded(final BluetoothDevice device) {
public void onBonded(@NonNull final BluetoothDevice device) {
// empty default implementation
}
@Override
public void onBondingFailed(final BluetoothDevice device) {
public void onBondingFailed(@NonNull final BluetoothDevice device) {
// empty default implementation
}
@Override
public void onDeviceNotSupported(final BluetoothDevice device) {
public void onDeviceNotSupported(@NonNull final BluetoothDevice device) {
showToast(R.string.not_supported);
}
@SuppressWarnings("deprecation")
@Override
public final boolean shouldEnableBatteryLevelNotifications(final BluetoothDevice device) {
public final boolean shouldEnableBatteryLevelNotifications(@NonNull final BluetoothDevice device) {
// This method will never be called.
// Please see BleMulticonnectProfileService#shouldEnableBatteryLevelNotifications(BluetoothDevice) instead.
throw new UnsupportedOperationException("This method should not be called");
}
@SuppressWarnings("deprecation")
@Override
public void onBatteryValueReceived(final BluetoothDevice device, final int value) {
public void onBatteryValueReceived(@NonNull final BluetoothDevice device, final int value) {
// empty default implementation
}
@Override
public void onError(final BluetoothDevice device, final String message, final int errorCode) {
public void onError(@NonNull final BluetoothDevice device, @NonNull final String message, final int errorCode) {
DebugLogger.e(TAG, "Error occurred: " + message + ", error code: " + errorCode);
showToast(message + " (" + errorCode + ")");
}
@@ -506,7 +513,7 @@ public abstract class BleMulticonnectProfileServiceReadyActivity<E extends BleMu
* @return unmodifiable list of managed devices
*/
protected List<BluetoothDevice> getManagedDevices() {
return Collections.unmodifiableList(mManagedDevices);
return Collections.unmodifiableList(managedDevices);
}
/**
@@ -514,7 +521,7 @@ public abstract class BleMulticonnectProfileServiceReadyActivity<E extends BleMu
* @param device the device to check if it's connected
*/
protected boolean isDeviceConnected(final BluetoothDevice device) {
return mService != null && mService.isConnected(device);
return service != null && service.isConnected(device);
}
/**
@@ -537,8 +544,7 @@ public abstract class BleMulticonnectProfileServiceReadyActivity<E extends BleMu
}
protected boolean isBLEEnabled() {
final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
final BluetoothAdapter adapter = bluetoothManager.getAdapter();
final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
return adapter != null && adapter.isEnabled();
}

View File

@@ -23,6 +23,8 @@
package no.nordicsemi.android.nrftoolbox.profile.multiconnect;
import android.bluetooth.BluetoothDevice;
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
public interface IDeviceLogger {
@@ -32,7 +34,7 @@ public interface IDeviceLogger {
* @param level the log level
* @param message the message to be logged
*/
void log(final BluetoothDevice device, final int level, final String message);
void log(@NonNull final BluetoothDevice device, final int level, final String message);
/**
* Logs the given message with given log level into the device's log session.
@@ -41,5 +43,5 @@ public interface IDeviceLogger {
* @param messageRes string resource id
* @param params additional (optional) parameters used to fill the message
*/
void log(final BluetoothDevice device, final int level, @StringRes final int messageRes, final Object... params);
void log(@NonNull final BluetoothDevice device, final int level, @StringRes final int messageRes, final Object... params);
}

View File

@@ -38,12 +38,12 @@ import java.util.List;
import no.nordicsemi.android.nrftoolbox.R;
public class DeviceAdapter extends RecyclerView.Adapter<DeviceAdapter.ViewHolder> {
private final ProximityService.ProximityBinder mService;
private final List<BluetoothDevice> mDevices;
private final ProximityService.ProximityBinder service;
private final List<BluetoothDevice> devices;
DeviceAdapter(final ProximityService.ProximityBinder binder) {
mService = binder;
mDevices = mService.getManagedDevices();
service = binder;
devices = service.getManagedDevices();
}
@NonNull
@@ -55,18 +55,18 @@ public class DeviceAdapter extends RecyclerView.Adapter<DeviceAdapter.ViewHolder
@Override
public void onBindViewHolder(@NonNull final ViewHolder holder, final int position) {
holder.bind(mDevices.get(position));
holder.bind(devices.get(position));
}
@Override
public int getItemCount() {
return mDevices.size();
return devices.size();
}
public void onDeviceAdded(final BluetoothDevice device) {
final int position = mDevices.indexOf(device);
final int position = devices.indexOf(device);
if (position == -1) {
notifyItemInserted(mDevices.size() - 1);
notifyItemInserted(devices.size() - 1);
} else {
// This may happen when Bluetooth adapter was switched off and on again
// while there were devices on the list.
@@ -79,13 +79,13 @@ public class DeviceAdapter extends RecyclerView.Adapter<DeviceAdapter.ViewHolder
}
public void onDeviceStateChanged(final BluetoothDevice device) {
final int position = mDevices.indexOf(device);
final int position = devices.indexOf(device);
if (position >= 0)
notifyItemChanged(position);
}
public void onBatteryValueReceived(final BluetoothDevice device) {
final int position = mDevices.indexOf(device);
final int position = devices.indexOf(device);
if (position >= 0)
notifyItemChanged(position);
}
@@ -109,22 +109,22 @@ public class DeviceAdapter extends RecyclerView.Adapter<DeviceAdapter.ViewHolder
// Configure FIND / SILENT button
actionButton.setOnClickListener(v -> {
final int position = getAdapterPosition();
final BluetoothDevice device = mDevices.get(position);
mService.toggleImmediateAlert(device);
final BluetoothDevice device = devices.get(position);
service.toggleImmediateAlert(device);
});
// Configure Disconnect button
itemView.findViewById(R.id.action_disconnect).setOnClickListener(v -> {
final int position = getAdapterPosition();
final BluetoothDevice device = mDevices.get(position);
mService.disconnect(device);
final BluetoothDevice device = devices.get(position);
service.disconnect(device);
// The device might have not been connected, so there will be no callback
onDeviceRemoved(device);
});
}
private void bind(final BluetoothDevice device) {
final boolean ready = mService.isReady(device);
final boolean ready = service.isReady(device);
String name = device.getName();
if (TextUtils.isEmpty(name))
@@ -132,12 +132,12 @@ public class DeviceAdapter extends RecyclerView.Adapter<DeviceAdapter.ViewHolder
nameView.setText(name);
addressView.setText(device.getAddress());
final boolean on = mService.isImmediateAlertOn(device);
final boolean on = service.isImmediateAlertOn(device);
actionButton.setImageResource(on ? R.drawable.ic_stat_notify_proximity_silent : R.drawable.ic_stat_notify_proximity_find);
actionButton.setVisibility(ready ? View.VISIBLE : View.GONE);
progress.setVisibility(ready ? View.GONE : View.VISIBLE);
final Integer batteryValue = mService.getBatteryLevel(device);
final Integer batteryValue = service.getBatteryLevel(device);
if (batteryValue != null) {
batteryView.getCompoundDrawables()[0 /*left*/].setLevel(batteryValue);
batteryView.setVisibility(View.VISIBLE);

View File

@@ -32,7 +32,7 @@ import no.nordicsemi.android.nrftoolbox.R;
public class LinkLossFragment extends DialogFragment {
private static final String ARG_NAME = "name";
private String mName;
private String name;
public static LinkLossFragment getInstance(String name) {
final LinkLossFragment fragment = new LinkLossFragment();
@@ -48,7 +48,7 @@ public class LinkLossFragment extends DialogFragment {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mName = getArguments().getString(ARG_NAME);
name = getArguments().getString(ARG_NAME);
}
@NonNull
@@ -56,7 +56,7 @@ public class LinkLossFragment extends DialogFragment {
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new AlertDialog.Builder(requireContext())
.setTitle(getString(R.string.app_name))
.setMessage(getString(R.string.proximity_notification_link_loss_alert, mName))
.setMessage(getString(R.string.proximity_notification_link_loss_alert, name))
.setPositiveButton(R.string.ok, null)
.create();
}

View File

@@ -28,6 +28,8 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@@ -40,8 +42,8 @@ import no.nordicsemi.android.nrftoolbox.profile.multiconnect.BleMulticonnectProf
import no.nordicsemi.android.nrftoolbox.widget.DividerItemDecoration;
public class ProximityActivity extends BleMulticonnectProfileServiceReadyActivity<ProximityService.ProximityBinder> {
private RecyclerView mDevicesView;
private DeviceAdapter mAdapter;
private RecyclerView devicesView;
private DeviceAdapter adapter;
@Override
protected void onCreateView(final Bundle savedInstanceState) {
@@ -51,17 +53,17 @@ public class ProximityActivity extends BleMulticonnectProfileServiceReadyActivit
@Override
protected void onInitialize(final Bundle savedInstanceState) {
LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, makeIntentFilter());
LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, makeIntentFilter());
}
@Override
protected void onDestroy() {
super.onDestroy();
LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver);
LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver);
}
private void setGUI() {
final RecyclerView recyclerView = mDevicesView = findViewById(android.R.id.list);
final RecyclerView recyclerView = devicesView = findViewById(android.R.id.list);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));
}
@@ -73,12 +75,12 @@ public class ProximityActivity extends BleMulticonnectProfileServiceReadyActivit
@Override
protected void onServiceBound(final ProximityService.ProximityBinder binder) {
mDevicesView.setAdapter(mAdapter = new DeviceAdapter(binder));
devicesView.setAdapter(adapter = new DeviceAdapter(binder));
}
@Override
protected void onServiceUnbound() {
mDevicesView.setAdapter(mAdapter = null);
devicesView.setAdapter(adapter = null);
}
@Override
@@ -97,46 +99,46 @@ public class ProximityActivity extends BleMulticonnectProfileServiceReadyActivit
}
@Override
public void onDeviceConnecting(final BluetoothDevice device) {
if (mAdapter != null)
mAdapter.onDeviceAdded(device);
public void onDeviceConnecting(@NonNull final BluetoothDevice device) {
if (adapter != null)
adapter.onDeviceAdded(device);
}
@Override
public void onDeviceConnected(final BluetoothDevice device) {
if (mAdapter != null)
mAdapter.onDeviceStateChanged(device);
if (adapter != null)
adapter.onDeviceStateChanged(device);
}
@Override
public void onDeviceReady(final BluetoothDevice device) {
if (mAdapter != null)
mAdapter.onDeviceStateChanged(device);
public void onDeviceReady(@NonNull final BluetoothDevice device) {
if (adapter != null)
adapter.onDeviceStateChanged(device);
}
@Override
public void onDeviceDisconnecting(final BluetoothDevice device) {
if (mAdapter != null)
mAdapter.onDeviceStateChanged(device);
public void onDeviceDisconnecting(@NonNull final BluetoothDevice device) {
if (adapter != null)
adapter.onDeviceStateChanged(device);
}
@Override
public void onDeviceDisconnected(final BluetoothDevice device) {
if (mAdapter != null)
mAdapter.onDeviceRemoved(device);
if (adapter != null)
adapter.onDeviceRemoved(device);
}
@Override
public void onDeviceNotSupported(final BluetoothDevice device) {
public void onDeviceNotSupported(@NonNull final BluetoothDevice device) {
super.onDeviceNotSupported(device);
if (mAdapter != null)
mAdapter.onDeviceRemoved(device);
if (adapter != null)
adapter.onDeviceRemoved(device);
}
@Override
public void onLinkLossOccurred(final BluetoothDevice device) {
if (mAdapter != null)
mAdapter.onDeviceStateChanged(device);
public void onLinkLossOccurred(@NonNull final BluetoothDevice device) {
if (adapter != null)
adapter.onDeviceStateChanged(device);
// The link loss may also be called when Bluetooth adapter was disabled
if (BluetoothAdapter.getDefaultAdapter().isEnabled())
@@ -145,14 +147,14 @@ public class ProximityActivity extends BleMulticonnectProfileServiceReadyActivit
@SuppressWarnings("unused")
private void onBatteryLevelChanged(final BluetoothDevice device, final int batteryLevel) {
if (mAdapter != null)
mAdapter.onBatteryValueReceived(device); // Value will be obtained from the service
if (adapter != null)
adapter.onBatteryValueReceived(device); // Value will be obtained from the service
}
@SuppressWarnings("unused")
private void onRemoteAlarmSwitched(final BluetoothDevice device, final boolean on) {
if (mAdapter != null)
mAdapter.onDeviceStateChanged(device); // Value will be obtained from the service
if (adapter != null)
adapter.onDeviceStateChanged(device); // Value will be obtained from the service
}
private void showLinkLossDialog(final String name) {
@@ -164,7 +166,7 @@ public class ProximityActivity extends BleMulticonnectProfileServiceReadyActivit
}
}
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
final String action = intent.getAction();

View File

@@ -21,8 +21,10 @@
*/
package no.nordicsemi.android.nrftoolbox.proximity;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattServer;
import android.bluetooth.BluetoothGattService;
import android.content.Context;
import androidx.annotation.NonNull;
@@ -31,6 +33,7 @@ import android.util.Log;
import java.util.UUID;
import no.nordicsemi.android.ble.callback.FailCallback;
import no.nordicsemi.android.ble.common.callback.alert.AlertLevelDataCallback;
import no.nordicsemi.android.ble.common.data.alert.AlertLevelData;
import no.nordicsemi.android.ble.error.GattError;
import no.nordicsemi.android.log.LogContract;
@@ -42,50 +45,67 @@ class ProximityManager extends BatteryManager<ProximityManagerCallbacks> {
/** Link Loss service UUID. */
final static UUID LINK_LOSS_SERVICE_UUID = UUID.fromString("00001803-0000-1000-8000-00805f9b34fb");
/** Immediate Alert service UUID. */
private final static UUID IMMEDIATE_ALERT_SERVICE_UUID = UUID.fromString("00001802-0000-1000-8000-00805f9b34fb");
final static UUID IMMEDIATE_ALERT_SERVICE_UUID = UUID.fromString("00001802-0000-1000-8000-00805f9b34fb");
/** Alert Level characteristic UUID. */
private static final UUID ALERT_LEVEL_CHARACTERISTIC_UUID = UUID.fromString("00002A06-0000-1000-8000-00805f9b34fb");
final static UUID ALERT_LEVEL_CHARACTERISTIC_UUID = UUID.fromString("00002A06-0000-1000-8000-00805f9b34fb");
private BluetoothGattCharacteristic mAlertLevelCharacteristic, mLinkLossCharacteristic;
private boolean mAlertOn;
// Client characteristics.
private BluetoothGattCharacteristic alertLevelCharacteristic, linkLossCharacteristic;
// Server characteristics.
private BluetoothGattCharacteristic localAlertLevelCharacteristic;
/** A flag indicating whether the alarm on the connected proximity tag has been activated. */
private boolean alertOn;
ProximityManager(final Context context) {
super(context);
}
@Override
protected boolean shouldAutoConnect() {
return true;
}
@NonNull
@Override
protected BatteryManagerGattCallback getGattCallback() {
return mGattCallback;
return gattCallback;
}
/**
* BluetoothGatt callbacks for connection/disconnection, service discovery,
* receiving indication, etc.
*/
private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() {
private final BatteryManagerGattCallback gattCallback = new BatteryManagerGattCallback() {
@Override
protected void initialize() {
super.initialize();
writeCharacteristic(mLinkLossCharacteristic, AlertLevelData.highAlert())
// This callback will be called whenever local Alert Level char is written
// by a connected proximity tag.
setWriteCallback(localAlertLevelCharacteristic)
.with(new AlertLevelDataCallback() {
@Override
public void onAlertLevelChanged(@NonNull final BluetoothDevice device, final int level) {
callbacks.onLocalAlarmSwitched(device, level != ALERT_NONE);
}
});
// After connection, set the Link Loss behaviour on the tag.
writeCharacteristic(linkLossCharacteristic, AlertLevelData.highAlert())
.done(device -> log(Log.INFO, "Link loss alert level set"))
.fail((device, status) -> log(Log.WARN, "Failed to set link loss level: " + status))
.enqueue();
}
@Override
protected void onServerReady(@NonNull final BluetoothGattServer server) {
final BluetoothGattService immediateAlertService = server.getService(IMMEDIATE_ALERT_SERVICE_UUID);
if (immediateAlertService != null) {
localAlertLevelCharacteristic = immediateAlertService.getCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID);
}
}
@Override
protected boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) {
final BluetoothGattService llService = gatt.getService(LINK_LOSS_SERVICE_UUID);
if (llService != null) {
mLinkLossCharacteristic = llService.getCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID);
linkLossCharacteristic = llService.getCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID);
}
return mLinkLossCharacteristic != null;
return linkLossCharacteristic != null;
}
@Override
@@ -93,18 +113,19 @@ class ProximityManager extends BatteryManager<ProximityManagerCallbacks> {
super.isOptionalServiceSupported(gatt);
final BluetoothGattService iaService = gatt.getService(IMMEDIATE_ALERT_SERVICE_UUID);
if (iaService != null) {
mAlertLevelCharacteristic = iaService.getCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID);
alertLevelCharacteristic = iaService.getCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID);
}
return mAlertLevelCharacteristic != null;
return alertLevelCharacteristic != null;
}
@Override
protected void onDeviceDisconnected() {
super.onDeviceDisconnected();
mAlertLevelCharacteristic = null;
mLinkLossCharacteristic = null;
alertLevelCharacteristic = null;
linkLossCharacteristic = null;
localAlertLevelCharacteristic = null;
// Reset the alert flag
mAlertOn = false;
alertOn = false;
}
};
@@ -112,7 +133,7 @@ class ProximityManager extends BatteryManager<ProximityManagerCallbacks> {
* Toggles the immediate alert on the target device.
*/
public void toggleImmediateAlert() {
writeImmediateAlert(!mAlertOn);
writeImmediateAlert(!alertOn);
}
/**
@@ -124,14 +145,14 @@ class ProximityManager extends BatteryManager<ProximityManagerCallbacks> {
if (!isConnected())
return;
writeCharacteristic(mAlertLevelCharacteristic, on ? AlertLevelData.highAlert() : AlertLevelData.noAlert())
writeCharacteristic(alertLevelCharacteristic, on ? AlertLevelData.highAlert() : AlertLevelData.noAlert())
.before(device -> log(Log.VERBOSE,
on ? "Setting alarm to HIGH..." : "Disabling alarm..."))
.with((device, data) -> log(LogContract.Log.Level.APPLICATION,
"\"" + AlertLevelParser.parse(data) + "\" sent"))
.done(device -> {
mAlertOn = on;
mCallbacks.onRemoteAlarmSwitched(device, on);
alertOn = on;
callbacks.onRemoteAlarmSwitched(device, on);
})
.fail((device, status) -> log(Log.WARN,
status == FailCallback.REASON_NULL_ATTRIBUTE ?
@@ -144,6 +165,6 @@ class ProximityManager extends BatteryManager<ProximityManagerCallbacks> {
* Returns true if the alert has been enabled on the proximity tag, false otherwise.
*/
boolean isAlertEnabled() {
return mAlertOn;
return alertOn;
}
}

View File

@@ -27,6 +27,7 @@ import androidx.annotation.NonNull;
import no.nordicsemi.android.nrftoolbox.battery.BatteryManagerCallbacks;
interface ProximityManagerCallbacks extends BatteryManagerCallbacks {
// No additional methods
void onRemoteAlarmSwitched(@NonNull final BluetoothDevice device, final boolean on);
void onLocalAlarmSwitched(@NonNull final BluetoothDevice device, final boolean on);
}

View File

@@ -21,366 +21,46 @@
*/
package no.nordicsemi.android.nrftoolbox.proximity;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattServer;
import android.bluetooth.BluetoothGattServerCallback;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.os.Handler;
import android.util.Log;
import java.util.UUID;
import java.util.ArrayList;
import java.util.List;
import no.nordicsemi.android.error.GattError;
import no.nordicsemi.android.log.LogContract;
import no.nordicsemi.android.nrftoolbox.parser.AlertLevelParser;
import no.nordicsemi.android.nrftoolbox.profile.multiconnect.IDeviceLogger;
import no.nordicsemi.android.nrftoolbox.utility.ParserUtils;
import androidx.annotation.NonNull;
import no.nordicsemi.android.ble.BleServerManager;
import no.nordicsemi.android.ble.common.data.alert.AlertLevelData;
class ProximityServerManager {
private final String TAG = "ProximityServerManager";
class ProximityServerManager extends BleServerManager {
/** Immediate Alert service UUID */
final static UUID IMMEDIATE_ALERT_SERVICE_UUID = UUID.fromString("00001802-0000-1000-8000-00805f9b34fb");
/** Linkloss service UUID */
final static UUID LINKLOSS_SERVICE_UUID = UUID.fromString("00001803-0000-1000-8000-00805f9b34fb");
/** Alert Level characteristic UUID */
private static final UUID ALERT_LEVEL_CHARACTERISTIC_UUID = UUID.fromString("00002A06-0000-1000-8000-00805f9b34fb");
private final static byte[] HIGH_ALERT = { 0x02 };
private final static byte[] MILD_ALERT = { 0x01 };
private final static byte[] NO_ALERT = { 0x00 };
private BluetoothGattServer mBluetoothGattServer;
private ProximityServerManagerCallbacks mCallbacks;
private IDeviceLogger mLogger;
private Handler mHandler;
private OnServerOpenCallback mOnServerOpenCallback;
private boolean mServerReady;
public interface OnServerOpenCallback {
/**
* Method called when the GATT server was created and all services were added successfully.
*/
void onGattServerOpen();
/**
* Method called when the GATT server failed to open and initialize services.
* -1 is returned when the server failed to start.
*/
void onGattServerFailed(final int error);
ProximityServerManager(@NonNull final Context context) {
super(context);
}
ProximityServerManager(final ProximityServerManagerCallbacks callbacks) {
mHandler = new Handler();
mCallbacks = callbacks;
@Override
public void log(final int priority, @NonNull final String message) {
Log.println(priority, "BleManager", message);
}
/**
* Sets the logger object. Logger is used to create logs in nRF Logger application.
*
* @param logger the logger object
*/
public void setLogger(final IDeviceLogger logger) {
mLogger = logger;
}
/**
* Opens GATT server and creates 2 services: Link Loss Service and Immediate Alert Service.
* The callback is called when initialization is complete.
*
* @param context the context.
* @param callback optional callback notifying when all services has been added.
*/
public void openGattServer(final Context context, final OnServerOpenCallback callback) {
// Is the server already open?
if (mBluetoothGattServer != null) {
if (callback != null)
callback.onGattServerOpen();
return;
}
mOnServerOpenCallback = callback;
final BluetoothManager manager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothGattServer = manager.openGattServer(context, mGattServerCallbacks);
if (mBluetoothGattServer != null) {
// Start adding services one by one. The onServiceAdded method will be called when it completes.
addImmediateAlertService();
} else {
if (callback != null)
callback.onGattServerFailed(-1);
mOnServerOpenCallback = null;
}
}
/**
* Returns true if GATT server was opened and configured correctly.
* False if hasn't been opened, was closed, of failed to start.
*/
public boolean isServerReady() {
return mServerReady;
}
/**
* Closes the GATT server. It will also disconnect all existing connections.
* If the service has already been closed, or hasn't been open, this method does nothing.
*/
public void closeGattServer() {
if (mBluetoothGattServer != null) {
mBluetoothGattServer.close();
mBluetoothGattServer = null;
mOnServerOpenCallback = null;
mServerReady = false;
}
}
/**
* This method notifies the Android that the Proximity profile will use the server connection
* to given device. If the server hasn't been open this method does nothing.
* The {@link #cancelConnection(BluetoothDevice)} method should be called when the connection
* is no longer used.
*
* @param device the target device.
*/
public void openConnection(final BluetoothDevice device) {
if (mBluetoothGattServer != null) {
mLogger.log(device, LogContract.Log.Level.VERBOSE, "[Server] Creating server connection...");
mLogger.log(device, LogContract.Log.Level.DEBUG, "server.connect(device, autoConnect = true)");
mBluetoothGattServer.connect(device, true); // In proximity the autoConnect is true
}
}
/**
* Cancels the connection to the given device. This notifies Android that this profile will
* no longer use this connection and it can be disconnected. In practice, this method does
* not disconnect, so if the remote device decides still to use the phone's GATT server it
* will be able to do so.
* <p>
* This bug/feature can be tested using a proximity tag that does not release its connection
* when it got disconnected:
* <ol>
* <li>Connect to your Proximity Tag.</li>
* <li>Verify that the bidirectional connection works - test the FIND ME button in
* nRF Toolbox and the FIND PHONE button on the tag.</li>
* <li>Disconnect from the tag</li>
* <li>When the device disappear from the list of devices click the FIND PHONE button on
* the tag. Your phone should still trigger an alarm, as the connection tag-&gt;phone
* is still active.</li>
* </ol>
* In order to avoid this issue make sure that your tag disconnects gently from phone when it
* got disconnected itself.
*
* @param device the device that will no longer be used.
*/
public void cancelConnection(final BluetoothDevice device) {
if (mBluetoothGattServer != null) {
mLogger.log(device, LogContract.Log.Level.VERBOSE, "[Server] Cancelling server connection...");
mLogger.log(device, LogContract.Log.Level.DEBUG, "server.cancelConnection(device)");
mBluetoothGattServer.cancelConnection(device);
}
}
private void addImmediateAlertService() {
/*
* This method must be called in UI thread. It works fine on Nexus devices but if called
* from other thread (e.g. from onServiceAdded in gatt server callback) it hangs the app.
*/
final BluetoothGattCharacteristic alertLevel =
new BluetoothGattCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID,
BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE,
BluetoothGattCharacteristic.PERMISSION_WRITE);
alertLevel.setValue(NO_ALERT);
final BluetoothGattService immediateAlertService =
new BluetoothGattService(IMMEDIATE_ALERT_SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY);
immediateAlertService.addCharacteristic(alertLevel);
mBluetoothGattServer.addService(immediateAlertService);
}
private void addLinkLossService() {
/*
* This method must be called in UI thread. It works fine on Nexus devices but if called
* from other thread (e.g. from onServiceAdded in gatt server callback) it hangs the app.
*/
final BluetoothGattCharacteristic linkLossAlertLevel =
new BluetoothGattCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID,
BluetoothGattCharacteristic.PROPERTY_WRITE | BluetoothGattCharacteristic.PROPERTY_READ,
BluetoothGattCharacteristic.PERMISSION_WRITE | BluetoothGattCharacteristic.PERMISSION_READ);
linkLossAlertLevel.setValue(HIGH_ALERT);
final BluetoothGattService linkLossService =
new BluetoothGattService(LINKLOSS_SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY);
linkLossService.addCharacteristic(linkLossAlertLevel);
mBluetoothGattServer.addService(linkLossService);
}
private final BluetoothGattServerCallback mGattServerCallbacks = new BluetoothGattServerCallback() {
@Override
public void onServiceAdded(final int status, final BluetoothGattService service) {
if (status == BluetoothGatt.GATT_SUCCESS) {
// Adding another service from callback thread fails on Samsung S4 with Android 4.3
mHandler.post(() -> {
if (IMMEDIATE_ALERT_SERVICE_UUID.equals(service.getUuid())) {
addLinkLossService();
} else {
mServerReady = true;
// Both services has been added
if (mOnServerOpenCallback != null)
mOnServerOpenCallback.onGattServerOpen();
mOnServerOpenCallback = null;
}
});
} else {
Log.e(TAG, "GATT Server failed to add service, status: " + status);
if (mOnServerOpenCallback != null)
mOnServerOpenCallback.onGattServerFailed(status);
mOnServerOpenCallback = null;
}
}
@Override
public void onConnectionStateChange(final BluetoothDevice device, final int status, final int newState) {
mLogger.log(device, LogContract.Log.Level.DEBUG,
"[Server callback] Connection state changed with status: " + status
+ " and new state: " + newState + " (" + stateToString(newState) + ")");
if (status == BluetoothGatt.GATT_SUCCESS) {
if (newState == BluetoothGatt.STATE_CONNECTED) {
mLogger.log(device, LogContract.Log.Level.INFO,
"[Server] Device with address " + device.getAddress() + " connected");
} else {
mLogger.log(device, LogContract.Log.Level.INFO, "[Server] Device disconnected");
mCallbacks.onAlarmStopped(device);
}
} else {
mLogger.log(device, LogContract.Log.Level.ERROR, "[Server] Error " + status +
" (0x" + Integer.toHexString(status) + "): " + GattError.parseConnectionError(status));
}
}
@Override
public void onCharacteristicReadRequest(final BluetoothDevice device, final int requestId,
final int offset, final BluetoothGattCharacteristic characteristic) {
mLogger.log(device, LogContract.Log.Level.DEBUG,
"[Server callback] Read request for characteristic " + characteristic.getUuid()
+ " (requestId=" + requestId + ", offset=" + offset + ")");
mLogger.log(device, LogContract.Log.Level.INFO,
"[Server] READ request for characteristic " + characteristic.getUuid() + " received");
byte[] value = characteristic.getValue();
if (value != null && offset > 0) {
byte[] offsetValue = new byte[value.length - offset];
System.arraycopy(value, offset, offsetValue, 0, offsetValue.length);
value = offsetValue;
}
if (value != null) {
mLogger.log(device, LogContract.Log.Level.DEBUG,
"server.sendResponse(GATT_SUCCESS, value=" + ParserUtils.parseDebug(value) + ")");
} else {
mLogger.log(device, LogContract.Log.Level.DEBUG, "server.sendResponse(GATT_SUCCESS, value=null)");
}
mBluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
mLogger.log(device, LogContract.Log.Level.VERBOSE, "[Server] Response sent");
}
@Override
public void onCharacteristicWriteRequest(final BluetoothDevice device, final int requestId,
final BluetoothGattCharacteristic characteristic, final boolean preparedWrite,
final boolean responseNeeded, final int offset, final byte[] value) {
mLogger.log(device, LogContract.Log.Level.DEBUG, "[Server callback] Write request to characteristic " + characteristic.getUuid()
+ " (requestId=" + requestId + ", prepareWrite=" + preparedWrite + ", responseNeeded=" + responseNeeded
+ ", offset=" + offset + ", value=" + ParserUtils.parseDebug(value) + ")");
final String writeType = !responseNeeded ? "WRITE NO RESPONSE" : "WRITE COMMAND";
mLogger.log(device, LogContract.Log.Level.INFO, "[Server] " + writeType
+ " request for characteristic " + characteristic.getUuid() + " received, value: " + ParserUtils.parse(value));
if (offset == 0) {
characteristic.setValue(value);
} else {
final byte[] currentValue = characteristic.getValue();
final byte[] newValue = new byte[currentValue.length + value.length];
System.arraycopy(currentValue, 0, newValue, 0, currentValue.length);
System.arraycopy(value, 0, newValue, offset, value.length);
characteristic.setValue(newValue);
}
if (!preparedWrite && value != null && value.length == 1) { // small validation
if (value[0] != NO_ALERT[0]) {
mLogger.log(device, LogContract.Log.Level.APPLICATION,
"[Server] Immediate alarm request received: " + AlertLevelParser.parse(characteristic));
mCallbacks.onAlarmTriggered(device);
} else {
mLogger.log(device, LogContract.Log.Level.APPLICATION,
"[Server] Immediate alarm request received: OFF");
mCallbacks.onAlarmStopped(device);
}
}
mLogger.log(device, LogContract.Log.Level.DEBUG, "server.sendResponse(GATT_SUCCESS, offset="
+ offset + ", value=" + ParserUtils.parseDebug(value) + ")");
mBluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, null);
mLogger.log(device, LogContract.Log.Level.VERBOSE, "[Server] Response sent");
}
@Override
public void onDescriptorReadRequest(final BluetoothDevice device, final int requestId,
final int offset, final BluetoothGattDescriptor descriptor) {
mLogger.log(device, LogContract.Log.Level.DEBUG,
"[Server callback] Write request to descriptor " + descriptor.getUuid() + " (requestId=" + requestId + ", offset=" + offset + ")");
mLogger.log(device, LogContract.Log.Level.INFO,
"[Server] READ request for descriptor " + descriptor.getUuid() + " received");
// This method is not supported
mLogger.log(device, LogContract.Log.Level.WARNING, "[Server] Operation not supported");
mLogger.log(device, LogContract.Log.Level.DEBUG, "[Server] server.sendResponse(GATT_REQUEST_NOT_SUPPORTED)");
mBluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED, offset, null);
mLogger.log(device, LogContract.Log.Level.VERBOSE, "[Server] Response sent");
}
@Override
public void onDescriptorWriteRequest(final BluetoothDevice device, final int requestId,
final BluetoothGattDescriptor descriptor, final boolean preparedWrite,
final boolean responseNeeded, final int offset, final byte[] value) {
mLogger.log(device, LogContract.Log.Level.DEBUG, "[Server callback] Write request to descriptor " + descriptor.getUuid()
+ " (requestId=" + requestId + ", prepareWrite=" + preparedWrite + ", responseNeeded=" + responseNeeded
+ ", offset=" + offset + ", value=" + ParserUtils.parse(value) + ")");
mLogger.log(device, LogContract.Log.Level.INFO, "[Server] READ request for descriptor " + descriptor.getUuid() + " received");
// This method is not supported
mLogger.log(device, LogContract.Log.Level.WARNING, "[Server] Operation not supported");
mLogger.log(device, LogContract.Log.Level.DEBUG, "[Server] server.sendResponse(GATT_REQUEST_NOT_SUPPORTED)");
mBluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED, offset, null);
mLogger.log(device, LogContract.Log.Level.VERBOSE, "[Server] Response sent");
}
@Override
public void onExecuteWrite(final BluetoothDevice device, final int requestId, final boolean execute) {
mLogger.log(device, LogContract.Log.Level.DEBUG,
"[Server callback] Execute write request (requestId=" + requestId + ", execute=" + execute + ")");
// This method is not supported
mLogger.log(device, LogContract.Log.Level.WARNING, "[Server] Operation not supported");
mLogger.log(device, LogContract.Log.Level.DEBUG, "[Server] server.sendResponse(GATT_REQUEST_NOT_SUPPORTED)");
mBluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED, 0, null);
mLogger.log(device, LogContract.Log.Level.VERBOSE, "[Server] Response sent");
}
};
/**
* Converts the connection state to String value.
*
* @param state the connection state.
* @return The state as String.
*/
private String stateToString(final int state) {
switch (state) {
case BluetoothProfile.STATE_CONNECTED:
return "CONNECTED";
case BluetoothProfile.STATE_CONNECTING:
return "CONNECTING";
case BluetoothProfile.STATE_DISCONNECTING:
return "DISCONNECTING";
default:
return "DISCONNECTED";
}
@NonNull
@Override
protected List<BluetoothGattService> initializeServer() {
final List<BluetoothGattService> services = new ArrayList<>();
services.add(
service(ProximityManager.IMMEDIATE_ALERT_SERVICE_UUID,
characteristic(ProximityManager.ALERT_LEVEL_CHARACTERISTIC_UUID,
BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE,
BluetoothGattCharacteristic.PERMISSION_WRITE))
);
services.add(
service(ProximityManager.LINK_LOSS_SERVICE_UUID,
characteristic(ProximityManager.ALERT_LEVEL_CHARACTERISTIC_UUID,
BluetoothGattCharacteristic.PROPERTY_WRITE | BluetoothGattCharacteristic.PROPERTY_READ,
BluetoothGattCharacteristic.PERMISSION_WRITE | BluetoothGattCharacteristic.PERMISSION_READ,
AlertLevelData.highAlert()))
);
return services;
}
}

View File

@@ -1,31 +0,0 @@
/*
* Copyright (c) 2015, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.nrftoolbox.proximity;
import android.bluetooth.BluetoothDevice;
import androidx.annotation.NonNull;
public interface ProximityServerManagerCallbacks {
void onAlarmTriggered(@NonNull final BluetoothDevice device);
void onAlarmStopped(@NonNull final BluetoothDevice device);
}

View File

@@ -47,6 +47,7 @@ import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import androidx.core.content.ContextCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import no.nordicsemi.android.ble.BleServerManagerCallbacks;
import no.nordicsemi.android.log.LogContract;
import no.nordicsemi.android.nrftoolbox.FeaturesActivity;
import no.nordicsemi.android.nrftoolbox.R;
@@ -54,7 +55,7 @@ import no.nordicsemi.android.nrftoolbox.ToolboxApplication;
import no.nordicsemi.android.nrftoolbox.profile.LoggableBleManager;
import no.nordicsemi.android.nrftoolbox.profile.multiconnect.BleMulticonnectProfileService;
public class ProximityService extends BleMulticonnectProfileService implements ProximityManagerCallbacks, ProximityServerManagerCallbacks {
public class ProximityService extends BleMulticonnectProfileService implements ProximityManagerCallbacks, BleServerManagerCallbacks {
@SuppressWarnings("unused")
private static final String TAG = "ProximityService";
@@ -75,30 +76,27 @@ public class ProximityService extends BleMulticonnectProfileService implements P
private final static int FIND_REQ = 2;
private final static int SILENT_REQ = 3;
private final ProximityBinder mBinder = new ProximityBinder();
private ProximityServerManager mServerManager;
private MediaPlayer mMediaPlayer;
private int mOriginalVolume;
private final ProximityBinder binder = new ProximityBinder();
private ProximityServerManager serverManager;
private MediaPlayer mediaPlayer;
private int originalVolume;
/**
* When a device starts an alarm on the phone it is added to this list.
* Alarm is disabled when this list is empty.
*/
private List<BluetoothDevice> mDevicesWithAlarm;
private int mAttempt;
private final static int MAX_ATTEMPTS = 1;
private List<BluetoothDevice> devicesWithAlarm;
/**
* This local binder is an interface for the bonded activity to operate with the proximity
* sensor.
*/
public class ProximityBinder extends LocalBinder {
class ProximityBinder extends LocalBinder {
/**
* Toggles the Immediate Alert on given remote device.
*
* @param device the connected device.
*/
public void toggleImmediateAlert(final BluetoothDevice device) {
void toggleImmediateAlert(final BluetoothDevice device) {
final ProximityManager manager = (ProximityManager) getBleManager(device);
manager.toggleImmediateAlert();
}
@@ -110,7 +108,7 @@ public class ProximityService extends BleMulticonnectProfileService implements P
* @param device the connected device.
* @return True if alarm has been enabled, false if disabled.
*/
public boolean isImmediateAlertOn(final BluetoothDevice device) {
boolean isImmediateAlertOn(final BluetoothDevice device) {
final ProximityManager manager = (ProximityManager) getBleManager(device);
return manager.isAlertEnabled();
}
@@ -122,7 +120,7 @@ public class ProximityService extends BleMulticonnectProfileService implements P
* @return Battery value or null if no value was received or Battery Level characteristic
* was not found, or the device is disconnected.
*/
public Integer getBatteryLevel(final BluetoothDevice device) {
Integer getBatteryLevel(final BluetoothDevice device) {
final ProximityManager manager = (ProximityManager) getBleManager(device);
return manager.getBatteryLevel();
}
@@ -130,24 +128,31 @@ public class ProximityService extends BleMulticonnectProfileService implements P
@Override
protected LocalBinder getBinder() {
return mBinder;
return binder;
}
@Override
protected LoggableBleManager<ProximityManagerCallbacks> initializeManager() {
return new ProximityManager(this);
final ProximityManager manager = new ProximityManager(this);
manager.useServer(serverManager);
return manager;
}
@Override
protected boolean shouldAutoConnect() {
return true;
}
/**
* This broadcast receiver listens for {@link #ACTION_DISCONNECT} that may be fired by pressing
* Disconnect action button on the notification.
*/
private final BroadcastReceiver mDisconnectActionBroadcastReceiver = new BroadcastReceiver() {
private final BroadcastReceiver disconnectActionBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
final BluetoothDevice device = intent.getParcelableExtra(EXTRA_DEVICE);
mBinder.log(device, LogContract.Log.Level.INFO, "[Notification] DISCONNECT action pressed");
mBinder.disconnect(device);
binder.log(device, LogContract.Log.Level.INFO, "[Notification] DISCONNECT action pressed");
binder.disconnect(device);
}
};
@@ -155,34 +160,34 @@ public class ProximityService extends BleMulticonnectProfileService implements P
* This broadcast receiver listens for {@link #ACTION_FIND} or {@link #ACTION_SILENT} that may
* be fired by pressing Find me action button on the notification.
*/
private final BroadcastReceiver mToggleAlarmActionBroadcastReceiver = new BroadcastReceiver() {
private final BroadcastReceiver toggleAlarmActionBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
final BluetoothDevice device = intent.getParcelableExtra(EXTRA_DEVICE);
switch (intent.getAction()) {
case ACTION_FIND:
mBinder.log(device, LogContract.Log.Level.INFO, "[Notification] FIND action pressed");
binder.log(device, LogContract.Log.Level.INFO, "[Notification] FIND action pressed");
break;
case ACTION_SILENT:
mBinder.log(device, LogContract.Log.Level.INFO, "[Notification] SILENT action pressed");
binder.log(device, LogContract.Log.Level.INFO, "[Notification] SILENT action pressed");
break;
}
mBinder.toggleImmediateAlert(device);
binder.toggleImmediateAlert(device);
}
};
@Override
protected void onServiceCreated() {
mServerManager = new ProximityServerManager(this);
mServerManager.setLogger(mBinder);
serverManager = new ProximityServerManager(this);
serverManager.setManagerCallbacks(this);
initializeAlarm();
registerReceiver(mDisconnectActionBroadcastReceiver, new IntentFilter(ACTION_DISCONNECT));
registerReceiver(disconnectActionBroadcastReceiver, new IntentFilter(ACTION_DISCONNECT));
final IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_FIND);
filter.addAction(ACTION_SILENT);
registerReceiver(mToggleAlarmActionBroadcastReceiver, filter);
registerReceiver(toggleAlarmActionBroadcastReceiver, filter);
}
@Override
@@ -190,55 +195,34 @@ public class ProximityService extends BleMulticonnectProfileService implements P
cancelNotifications();
// Close the GATT server. If it hasn't been opened this method does nothing
mServerManager.closeGattServer();
serverManager.close();
serverManager = null;
releaseAlarm();
unregisterReceiver(mDisconnectActionBroadcastReceiver);
unregisterReceiver(mToggleAlarmActionBroadcastReceiver);
unregisterReceiver(disconnectActionBroadcastReceiver);
unregisterReceiver(toggleAlarmActionBroadcastReceiver);
super.onServiceStopped();
}
@Override
protected void onBluetoothEnabled() {
mAttempt = 0;
getHandler().post(new Runnable() {
@Override
public void run() {
final Runnable that = this;
// Start the GATT Server only if Bluetooth is enabled
mServerManager.openGattServer(ProximityService.this,
new ProximityServerManager.OnServerOpenCallback() {
@Override
public void onGattServerOpen() {
// We are now ready to reconnect devices
ProximityService.super.onBluetoothEnabled();
}
// First, open the server. onServerReady() will be called when all services were added.
serverManager.open();
}
@Override
public void onGattServerFailed(final int error) {
mServerManager.closeGattServer();
if (mAttempt < MAX_ATTEMPTS) {
mAttempt++;
getHandler().postDelayed(that, 2000);
} else {
showToast(getString(R.string.proximity_server_error, error));
// GATT server failed to start, but we may connect as a client
ProximityService.super.onBluetoothEnabled();
}
}
});
}
});
@Override
public void onServerReady() {
// This will start reconnecting to devices that will previously connected.
super.onBluetoothEnabled();
}
@Override
protected void onBluetoothDisabled() {
super.onBluetoothDisabled();
// Close the GATT server
mServerManager.closeGattServer();
serverManager.close();
}
@Override
@@ -270,27 +254,25 @@ public class ProximityService extends BleMulticonnectProfileService implements P
}
@Override
public void onDeviceConnected(final BluetoothDevice device) {
public void onDeviceConnected(@NonNull final BluetoothDevice device) {
super.onDeviceConnected(device);
if (!mBound) {
if (!bound) {
createBackgroundNotification();
}
}
@Override
public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) {
super.onServicesDiscovered(device, optionalServicesFound);
mServerManager.openConnection(device);
public void onDeviceConnectedToServer(@NonNull final BluetoothDevice device) {
binder.log(Log.INFO, device.getAddress() + " connected to server");
}
@Override
public void onLinkLossOccurred(final BluetoothDevice device) {
mServerManager.cancelConnection(device);
public void onLinkLossOccurred(@NonNull final BluetoothDevice device) {
stopAlarm(device);
super.onLinkLossOccurred(device);
if (!mBound) {
if (!bound) {
createBackgroundNotification();
if (BluetoothAdapter.getDefaultAdapter().isEnabled())
createLinkLossNotification(device);
@@ -300,25 +282,19 @@ public class ProximityService extends BleMulticonnectProfileService implements P
}
@Override
public void onDeviceDisconnected(final BluetoothDevice device) {
mServerManager.cancelConnection(device);
public void onDeviceDisconnected(@NonNull final BluetoothDevice device) {
stopAlarm(device);
super.onDeviceDisconnected(device);
if (!mBound) {
if (!bound) {
cancelNotification(device);
createBackgroundNotification();
}
}
@Override
public void onAlarmTriggered(@NonNull final BluetoothDevice device) {
playAlarm(device);
}
@Override
public void onAlarmStopped(@NonNull final BluetoothDevice device) {
stopAlarm(device);
public void onDeviceDisconnectedFromServer(@NonNull final BluetoothDevice device) {
binder.log(Log.INFO, device.getAddress() + " disconnected from server");
}
@Override
@@ -328,11 +304,19 @@ public class ProximityService extends BleMulticonnectProfileService implements P
broadcast.putExtra(EXTRA_ALARM_STATE, on);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
if (!mBound) {
if (!bound) {
createBackgroundNotification();
}
}
@Override
public void onLocalAlarmSwitched(@NonNull final BluetoothDevice device, final boolean on) {
if (on)
playAlarm(device);
else
stopAlarm(device);
}
@Override
public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) {
final Intent broadcast = new Intent(BROADCAST_BATTERY_LEVEL);
@@ -537,36 +521,36 @@ public class ProximityService extends BleMulticonnectProfileService implements P
}
private void initializeAlarm() {
mDevicesWithAlarm = new LinkedList<>();
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
mMediaPlayer.setLooping(true);
mMediaPlayer.setVolume(1.0f, 1.0f);
devicesWithAlarm = new LinkedList<>();
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
mediaPlayer.setLooping(true);
mediaPlayer.setVolume(1.0f, 1.0f);
try {
mMediaPlayer.setDataSource(this, RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM));
mediaPlayer.setDataSource(this, RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM));
} catch (final IOException e) {
Log.e(TAG, "Initialize Alarm failed: ", e);
}
}
private void releaseAlarm() {
mMediaPlayer.release();
mMediaPlayer = null;
mediaPlayer.release();
mediaPlayer = null;
}
private void playAlarm(final BluetoothDevice device) {
final boolean alarmPlaying = !mDevicesWithAlarm.isEmpty();
if (!mDevicesWithAlarm.contains(device))
mDevicesWithAlarm.add(device);
final boolean alarmPlaying = !devicesWithAlarm.isEmpty();
if (!devicesWithAlarm.contains(device))
devicesWithAlarm.add(device);
if (!alarmPlaying) {
// Save the current alarm volume and set it to max
final AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
mOriginalVolume = am.getStreamVolume(AudioManager.STREAM_ALARM);
originalVolume = am.getStreamVolume(AudioManager.STREAM_ALARM);
am.setStreamVolume(AudioManager.STREAM_ALARM, am.getStreamMaxVolume(AudioManager.STREAM_ALARM), AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
try {
mMediaPlayer.prepare();
mMediaPlayer.start();
mediaPlayer.prepare();
mediaPlayer.start();
} catch (final IOException e) {
Log.e(TAG, "Prepare Alarm failed: ", e);
}
@@ -574,12 +558,12 @@ public class ProximityService extends BleMulticonnectProfileService implements P
}
private void stopAlarm(final BluetoothDevice device) {
mDevicesWithAlarm.remove(device);
if (mDevicesWithAlarm.isEmpty() && mMediaPlayer.isPlaying()) {
mMediaPlayer.stop();
devicesWithAlarm.remove(device);
if (devicesWithAlarm.isEmpty() && mediaPlayer.isPlaying()) {
mediaPlayer.stop();
// Restore original volume
final AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
am.setStreamVolume(AudioManager.STREAM_ALARM, mOriginalVolume, 0);
am.setStreamVolume(AudioManager.STREAM_ALARM, originalVolume, 0);
}
}

View File

@@ -30,6 +30,8 @@ import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import androidx.annotation.NonNull;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import android.view.Menu;
import android.widget.TextView;
@@ -44,16 +46,16 @@ import no.nordicsemi.android.nrftoolbox.rsc.settings.SettingsActivity;
import no.nordicsemi.android.nrftoolbox.rsc.settings.SettingsFragment;
public class RSCActivity extends BleProfileServiceReadyActivity<RSCService.RSCBinder> {
private TextView mSpeedView;
private TextView mSpeedUnitView;
private TextView mCadenceView;
private TextView mDistanceView;
private TextView mDistanceUnitView;
private TextView mTotalDistanceView;
private TextView mTotalDistanceUnitView;
private TextView mStridesCountView;
private TextView mActivityView;
private TextView mBatteryLevelView;
private TextView speedView;
private TextView speedUnitView;
private TextView cadenceView;
private TextView distanceView;
private TextView distanceUnitView;
private TextView totalDistanceView;
private TextView totalDistanceUnitView;
private TextView stridesCountView;
private TextView activityView;
private TextView batteryLevelView;
@Override
protected void onCreateView(final Bundle savedInstanceState) {
@@ -63,26 +65,26 @@ public class RSCActivity extends BleProfileServiceReadyActivity<RSCService.RSCBi
@Override
protected void onInitialize(final Bundle savedInstanceState) {
LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, makeIntentFilter());
LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, makeIntentFilter());
}
@Override
protected void onDestroy() {
super.onDestroy();
LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver);
LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver);
}
private void setGui() {
mSpeedView = findViewById(R.id.speed);
mSpeedUnitView = findViewById(R.id.speed_unit);
mCadenceView = findViewById(R.id.cadence);
mDistanceView = findViewById(R.id.distance);
mDistanceUnitView = findViewById(R.id.distance_unit);
mTotalDistanceView = findViewById(R.id.total_distance);
mTotalDistanceUnitView = findViewById(R.id.total_distance_unit);
mStridesCountView = findViewById(R.id.strides);
mActivityView = findViewById(R.id.activity);
mBatteryLevelView = findViewById(R.id.battery);
speedView = findViewById(R.id.speed);
speedUnitView = findViewById(R.id.speed_unit);
cadenceView = findViewById(R.id.cadence);
distanceView = findViewById(R.id.distance);
distanceUnitView = findViewById(R.id.distance_unit);
totalDistanceView = findViewById(R.id.total_distance);
totalDistanceUnitView = findViewById(R.id.total_distance_unit);
stridesCountView = findViewById(R.id.strides);
activityView = findViewById(R.id.activity);
batteryLevelView = findViewById(R.id.battery);
}
@Override
@@ -93,13 +95,13 @@ public class RSCActivity extends BleProfileServiceReadyActivity<RSCService.RSCBi
@Override
protected void setDefaultUI() {
mSpeedView.setText(R.string.not_available_value);
mCadenceView.setText(R.string.not_available_value);
mDistanceView.setText(R.string.not_available_value);
mTotalDistanceView.setText(R.string.not_available_value);
mStridesCountView.setText(R.string.not_available_value);
mActivityView.setText(R.string.not_available);
mBatteryLevelView.setText(R.string.not_available);
speedView.setText(R.string.not_available_value);
cadenceView.setText(R.string.not_available_value);
distanceView.setText(R.string.not_available_value);
totalDistanceView.setText(R.string.not_available_value);
stridesCountView.setText(R.string.not_available_value);
activityView.setText(R.string.not_available);
batteryLevelView.setText(R.string.not_available);
setUnits();
}
@@ -110,19 +112,19 @@ public class RSCActivity extends BleProfileServiceReadyActivity<RSCService.RSCBi
switch (unit) {
case SettingsFragment.SETTINGS_UNIT_M_S: // [m/s]
mSpeedUnitView.setText(R.string.rsc_speed_unit_m_s);
mDistanceUnitView.setText(R.string.rsc_distance_unit_m);
mTotalDistanceUnitView.setText(R.string.rsc_total_distance_unit_km);
speedUnitView.setText(R.string.rsc_speed_unit_m_s);
distanceUnitView.setText(R.string.rsc_distance_unit_m);
totalDistanceUnitView.setText(R.string.rsc_total_distance_unit_km);
break;
case SettingsFragment.SETTINGS_UNIT_KM_H: // [km/h]
mSpeedUnitView.setText(R.string.rsc_speed_unit_km_h);
mDistanceUnitView.setText(R.string.rsc_distance_unit_m);
mTotalDistanceUnitView.setText(R.string.rsc_total_distance_unit_km);
speedUnitView.setText(R.string.rsc_speed_unit_km_h);
distanceUnitView.setText(R.string.rsc_distance_unit_m);
totalDistanceUnitView.setText(R.string.rsc_total_distance_unit_km);
break;
case SettingsFragment.SETTINGS_UNIT_MPH: // [mph]
mSpeedUnitView.setText(R.string.rsc_speed_unit_mph);
mDistanceUnitView.setText(R.string.rsc_distance_unit_yd);
mTotalDistanceUnitView.setText(R.string.rsc_total_distance_unit_mile);
speedUnitView.setText(R.string.rsc_speed_unit_mph);
distanceUnitView.setText(R.string.rsc_distance_unit_yd);
totalDistanceUnitView.setText(R.string.rsc_total_distance_unit_mile);
break;
}
}
@@ -180,14 +182,14 @@ public class RSCActivity extends BleProfileServiceReadyActivity<RSCService.RSCBi
}
@Override
public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) {
public void onServicesDiscovered(@NonNull final BluetoothDevice device, final boolean optionalServicesFound) {
// not used
}
@Override
public void onDeviceDisconnected(final BluetoothDevice device) {
public void onDeviceDisconnected(@NonNull final BluetoothDevice device) {
super.onDeviceDisconnected(device);
mBatteryLevelView.setText(R.string.not_available);
batteryLevelView.setText(R.string.not_available);
}
private void onMeasurementReceived(float speed, int cadence, long totalDistance, final boolean running) {
@@ -200,34 +202,34 @@ public class RSCActivity extends BleProfileServiceReadyActivity<RSCService.RSCBi
// pass through intended
case SettingsFragment.SETTINGS_UNIT_M_S:
if (totalDistance == -1) {
mTotalDistanceView.setText(R.string.not_available);
mTotalDistanceUnitView.setText(null);
totalDistanceView.setText(R.string.not_available);
totalDistanceUnitView.setText(null);
} else {
mTotalDistanceView.setText(String.format(Locale.US, "%.2f", totalDistance / 1000.0f)); // 1 km in m
mTotalDistanceUnitView.setText(R.string.rsc_total_distance_unit_km);
totalDistanceView.setText(String.format(Locale.US, "%.2f", totalDistance / 1000.0f)); // 1 km in m
totalDistanceUnitView.setText(R.string.rsc_total_distance_unit_km);
}
break;
case SettingsFragment.SETTINGS_UNIT_MPH:
speed = speed * 2.2369f;
if (totalDistance == -1) {
mTotalDistanceView.setText(R.string.not_available);
mTotalDistanceUnitView.setText(null);
totalDistanceView.setText(R.string.not_available);
totalDistanceUnitView.setText(null);
} else {
mTotalDistanceView.setText(String.format(Locale.US, "%.2f", totalDistance / 1609.31f)); // 1 mile in m
mTotalDistanceUnitView.setText(R.string.rsc_total_distance_unit_mile);
totalDistanceView.setText(String.format(Locale.US, "%.2f", totalDistance / 1609.31f)); // 1 mile in m
totalDistanceUnitView.setText(R.string.rsc_total_distance_unit_mile);
}
break;
}
mSpeedView.setText(String.format(Locale.US, "%.1f", speed));
mCadenceView.setText(String.format(Locale.US, "%d", cadence));
mActivityView.setText(running ? R.string.rsc_running : R.string.rsc_walking);
speedView.setText(String.format(Locale.US, "%.1f", speed));
cadenceView.setText(String.format(Locale.US, "%d", cadence));
activityView.setText(running ? R.string.rsc_running : R.string.rsc_walking);
}
private void onStripesUpdate(final long distance, final int strides) {
if (distance == -1) {
mDistanceView.setText(R.string.not_available);
mDistanceUnitView.setText(R.string.rsc_distance_unit_m);
distanceView.setText(R.string.not_available);
distanceUnitView.setText(R.string.rsc_distance_unit_m);
} else {
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
final int unit = Integer.parseInt(preferences.getString(SettingsFragment.SETTINGS_UNIT, String.valueOf(SettingsFragment.SETTINGS_UNIT_DEFAULT)));
@@ -236,29 +238,29 @@ public class RSCActivity extends BleProfileServiceReadyActivity<RSCService.RSCBi
case SettingsFragment.SETTINGS_UNIT_KM_H:
case SettingsFragment.SETTINGS_UNIT_M_S:
if (distance < 100000L) { // 1 km in cm
mDistanceView.setText(String.format(Locale.US, "%.1f", distance / 100.0f));
mDistanceUnitView.setText(R.string.rsc_distance_unit_m);
distanceView.setText(String.format(Locale.US, "%.1f", distance / 100.0f));
distanceUnitView.setText(R.string.rsc_distance_unit_m);
} else {
mDistanceView.setText(String.format(Locale.US, "%.2f", distance / 100000.0f));
mDistanceUnitView.setText(R.string.rsc_distance_unit_km);
distanceView.setText(String.format(Locale.US, "%.2f", distance / 100000.0f));
distanceUnitView.setText(R.string.rsc_distance_unit_km);
}
break;
case SettingsFragment.SETTINGS_UNIT_MPH:
if (distance < 160931L) { // 1 mile in cm
mDistanceView.setText(String.format(Locale.US, "%.1f", distance / 91.4392f));
mDistanceUnitView.setText(R.string.rsc_distance_unit_yd);
distanceView.setText(String.format(Locale.US, "%.1f", distance / 91.4392f));
distanceUnitView.setText(R.string.rsc_distance_unit_yd);
} else {
mDistanceView.setText(String.format(Locale.US, "%.2f", distance / 160931.23f));
mDistanceUnitView.setText(R.string.rsc_distance_unit_mile);
distanceView.setText(String.format(Locale.US, "%.2f", distance / 160931.23f));
distanceUnitView.setText(R.string.rsc_distance_unit_mile);
}
break;
}
}
mStridesCountView.setText(String.valueOf(strides));
stridesCountView.setText(String.valueOf(strides));
}
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
final String action = intent.getAction();

View File

@@ -40,11 +40,11 @@ import no.nordicsemi.android.nrftoolbox.parser.RSCMeasurementParser;
public class RSCManager extends BatteryManager<RSCManagerCallbacks> {
/** Running Speed and Cadence Measurement service UUID */
public static final UUID RUNNING_SPEED_AND_CADENCE_SERVICE_UUID = UUID.fromString("00001814-0000-1000-8000-00805f9b34fb");
static final UUID RUNNING_SPEED_AND_CADENCE_SERVICE_UUID = UUID.fromString("00001814-0000-1000-8000-00805f9b34fb");
/** Running Speed and Cadence Measurement characteristic UUID */
private static final UUID RSC_MEASUREMENT_CHARACTERISTIC_UUID = UUID.fromString("00002A53-0000-1000-8000-00805f9b34fb");
private BluetoothGattCharacteristic mRSCMeasurementCharacteristic;
private BluetoothGattCharacteristic rscMeasurementCharacteristic;
RSCManager(final Context context) {
super(context);
@@ -53,19 +53,19 @@ public class RSCManager extends BatteryManager<RSCManagerCallbacks> {
@NonNull
@Override
protected BatteryManagerGattCallback getGattCallback() {
return mGattCallback;
return gattCallback;
}
/**
* BluetoothGatt callbacks for connection/disconnection, service discovery,
* receiving indication, etc.
*/
private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() {
private final BatteryManagerGattCallback gattCallback = new BatteryManagerGattCallback() {
@Override
protected void initialize() {
super.initialize();
setNotificationCallback(mRSCMeasurementCharacteristic)
setNotificationCallback(rscMeasurementCharacteristic)
.with(new RunningSpeedAndCadenceMeasurementDataCallback() {
@Override
public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
@@ -78,26 +78,26 @@ public class RSCManager extends BatteryManager<RSCManagerCallbacks> {
final float instantaneousSpeed, final int instantaneousCadence,
@Nullable final Integer strideLength,
@Nullable final Long totalDistance) {
mCallbacks.onRSCMeasurementReceived(device, running, instantaneousSpeed,
callbacks.onRSCMeasurementReceived(device, running, instantaneousSpeed,
instantaneousCadence, strideLength, totalDistance);
}
});
enableNotifications(mRSCMeasurementCharacteristic).enqueue();
enableNotifications(rscMeasurementCharacteristic).enqueue();
}
@Override
public boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) {
final BluetoothGattService service = gatt.getService(RUNNING_SPEED_AND_CADENCE_SERVICE_UUID);
if (service != null) {
mRSCMeasurementCharacteristic = service.getCharacteristic(RSC_MEASUREMENT_CHARACTERISTIC_UUID);
rscMeasurementCharacteristic = service.getCharacteristic(RSC_MEASUREMENT_CHARACTERISTIC_UUID);
}
return mRSCMeasurementCharacteristic != null;
return rscMeasurementCharacteristic != null;
}
@Override
protected void onDeviceDisconnected() {
super.onDeviceDisconnected();
mRSCMeasurementCharacteristic = null;
rscMeasurementCharacteristic = null;
}
};
}

View File

@@ -45,6 +45,7 @@ import no.nordicsemi.android.nrftoolbox.profile.BleProfileService;
import no.nordicsemi.android.nrftoolbox.profile.LoggableBleManager;
public class RSCService extends BleProfileService implements RSCManagerCallbacks {
@SuppressWarnings("unused")
private static final String TAG = "RSCService";
public static final String BROADCAST_RSC_MEASUREMENT = "no.nordicsemi.android.nrftoolbox.rsc.BROADCAST_RSC_MEASUREMENT";
@@ -63,32 +64,32 @@ public class RSCService extends BleProfileService implements RSCManagerCallbacks
private final static String ACTION_DISCONNECT = "no.nordicsemi.android.nrftoolbox.rsc.ACTION_DISCONNECT";
private RSCManager mManager;
private RSCManager manager;
/**
* The last value of a cadence
*/
private float mCadence;
private float cadence;
/**
* Trip distance in cm
*/
private long mDistance;
private long distance;
/**
* Stride length in cm
*/
private Integer mStrideLength;
private Integer strideLength;
/**
* Number of steps in the trip
*/
private int mStepsNumber;
private boolean mTaskInProgress;
private final Handler mHandler = new Handler();
private int stepsNumber;
private boolean taskInProgress;
private final Handler handler = new Handler();
private final static int NOTIFICATION_ID = 200;
private final static int OPEN_ACTIVITY_REQ = 0;
private final static int DISCONNECT_REQ = 1;
private final LocalBinder mBinder = new RSCBinder();
private final LocalBinder binder = new RSCBinder();
/**
* This local binder is an interface for the bound activity to operate with the RSC sensor.
@@ -99,12 +100,12 @@ public class RSCService extends BleProfileService implements RSCManagerCallbacks
@Override
protected LocalBinder getBinder() {
return mBinder;
return binder;
}
@Override
protected LoggableBleManager<RSCManagerCallbacks> initializeManager() {
return mManager = new RSCManager(this);
return manager = new RSCManager(this);
}
@Override
@@ -113,14 +114,14 @@ public class RSCService extends BleProfileService implements RSCManagerCallbacks
final IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_DISCONNECT);
registerReceiver(mDisconnectActionBroadcastReceiver, filter);
registerReceiver(disconnectActionBroadcastReceiver, filter);
}
@Override
public void onDestroy() {
// when user has disconnected from the sensor, we have to cancel the notification that we've created some milliseconds before using unbindService
stopForegroundService();
unregisterReceiver(mDisconnectActionBroadcastReceiver);
unregisterReceiver(disconnectActionBroadcastReceiver);
super.onDestroy();
}
@@ -132,7 +133,7 @@ public class RSCService extends BleProfileService implements RSCManagerCallbacks
if (isConnected()) {
// This method will read the Battery Level value, if possible and then try to enable battery notifications (if it has NOTIFY property).
// If the Battery Level characteristic has only the NOTIFY property, it will only try to enable notifications.
mManager.readBatteryLevelCharacteristic();
manager.readBatteryLevelCharacteristic();
}
}
@@ -141,29 +142,29 @@ public class RSCService extends BleProfileService implements RSCManagerCallbacks
// When we are connected, but the application is not open, we are not really interested in battery level notifications.
// But we will still be receiving other values, if enabled.
if (isConnected())
mManager.disableBatteryLevelCharacteristicNotifications();
manager.disableBatteryLevelCharacteristicNotifications();
startForegroundService();
}
private final Runnable mUpdateStridesTask = new Runnable() {
private final Runnable updateStridesTask = new Runnable() {
@Override
public void run() {
if (!isConnected())
return;
mStepsNumber++;
mDistance += mStrideLength; // [cm]
stepsNumber++;
distance += strideLength; // [cm]
final Intent broadcast = new Intent(BROADCAST_STRIDES_UPDATE);
broadcast.putExtra(EXTRA_STRIDES, mStepsNumber);
broadcast.putExtra(EXTRA_DISTANCE, mDistance);
broadcast.putExtra(EXTRA_STRIDES, stepsNumber);
broadcast.putExtra(EXTRA_DISTANCE, distance);
LocalBroadcastManager.getInstance(RSCService.this).sendBroadcast(broadcast);
if (mCadence > 0) {
final long interval = (long) (1000.0f * 60.0f / mCadence);
mHandler.postDelayed(mUpdateStridesTask, interval);
if (cadence > 0) {
final long interval = (long) (1000.0f * 60.0f / cadence);
handler.postDelayed(updateStridesTask, interval);
} else {
mTaskInProgress = false;
taskInProgress = false;
}
}
};
@@ -183,15 +184,15 @@ public class RSCService extends BleProfileService implements RSCManagerCallbacks
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
// Start strides counter if not in progress
mCadence = instantaneousCadence;
cadence = instantaneousCadence;
if (strideLength != null) {
mStrideLength = strideLength;
this.strideLength = strideLength;
}
if (!mTaskInProgress && strideLength != null && instantaneousCadence > 0) {
mTaskInProgress = true;
if (!taskInProgress && strideLength != null && instantaneousCadence > 0) {
taskInProgress = true;
final long interval = (long) (1000.0f * 60.0f / mCadence);
mHandler.postDelayed(mUpdateStridesTask, interval);
final long interval = (long) (1000.0f * 60.0f / cadence);
handler.postDelayed(updateStridesTask, interval);
}
}
@@ -238,6 +239,7 @@ public class RSCService extends BleProfileService implements RSCManagerCallbacks
* f.e. <code>&lt;string name="name"&gt;%s is connected&lt;/string&gt;</code>
* @param defaults
*/
@SuppressWarnings("SameParameterValue")
private Notification createNotification(final int messageResId, final int defaults) {
final Intent parentIntent = new Intent(this, FeaturesActivity.class);
parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -269,7 +271,7 @@ public class RSCService extends BleProfileService implements RSCManagerCallbacks
/**
* This broadcast receiver listens for {@link #ACTION_DISCONNECT} that may be fired by pressing Disconnect action button on the notification.
*/
private final BroadcastReceiver mDisconnectActionBroadcastReceiver = new BroadcastReceiver() {
private final BroadcastReceiver disconnectActionBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
Logger.i(getLogSession(), "[Notification] Disconnect action pressed");

View File

@@ -22,7 +22,6 @@
package no.nordicsemi.android.nrftoolbox.scanner;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -34,33 +33,32 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import no.nordicsemi.android.nrftoolbox.R;
import no.nordicsemi.android.support.v18.scanner.ScanResult;
/**
* DeviceListAdapter class is list adapter for showing scanned Devices name, address and RSSI image based on RSSI values.
*/
public class DeviceListAdapter extends BaseAdapter {
class DeviceListAdapter extends BaseAdapter {
private static final int TYPE_TITLE = 0;
private static final int TYPE_ITEM = 1;
private static final int TYPE_EMPTY = 2;
private final ArrayList<ExtendedBluetoothDevice> mListBondedValues = new ArrayList<>();
private final ArrayList<ExtendedBluetoothDevice> mListValues = new ArrayList<>();
private final Context mContext;
private final ArrayList<ExtendedBluetoothDevice> listBondedValues = new ArrayList<>();
private final ArrayList<ExtendedBluetoothDevice> listValues = new ArrayList<>();
public DeviceListAdapter(final Context context) {
mContext = context;
DeviceListAdapter() {
}
/**
* Sets a list of bonded devices.
* @param devices list of bonded devices.
*/
public void addBondedDevices(final Set<BluetoothDevice> devices) {
final List<ExtendedBluetoothDevice> bondedDevices = mListBondedValues;
void addBondedDevices(@NonNull final Set<BluetoothDevice> devices) {
for (BluetoothDevice device : devices) {
bondedDevices.add(new ExtendedBluetoothDevice(device));
listBondedValues.add(new ExtendedBluetoothDevice(device));
}
notifyDataSetChanged();
}
@@ -69,11 +67,11 @@ public class DeviceListAdapter extends BaseAdapter {
* Updates the list of not bonded devices.
* @param results list of results from the scanner
*/
public void update(final List<ScanResult> results) {
public void update(@NonNull final List<ScanResult> results) {
for (final ScanResult result : results) {
final ExtendedBluetoothDevice device = findDevice(result);
if (device == null) {
mListValues.add(new ExtendedBluetoothDevice(result));
listValues.add(new ExtendedBluetoothDevice(result));
} else {
device.name = result.getScanRecord() != null ? result.getScanRecord().getDeviceName() : null;
device.rssi = result.getRssi();
@@ -82,46 +80,46 @@ public class DeviceListAdapter extends BaseAdapter {
notifyDataSetChanged();
}
private ExtendedBluetoothDevice findDevice(final ScanResult result) {
for (final ExtendedBluetoothDevice device : mListBondedValues)
private ExtendedBluetoothDevice findDevice(@NonNull final ScanResult result) {
for (final ExtendedBluetoothDevice device : listBondedValues)
if (device.matches(result))
return device;
for (final ExtendedBluetoothDevice device : mListValues)
for (final ExtendedBluetoothDevice device : listValues)
if (device.matches(result))
return device;
return null;
}
public void clearDevices() {
mListValues.clear();
void clearDevices() {
listValues.clear();
notifyDataSetChanged();
}
@Override
public int getCount() {
final int bondedCount = mListBondedValues.size() + 1; // 1 for the title
final int availableCount = mListValues.isEmpty() ? 2 : mListValues.size() + 1; // 1 for title, 1 for empty text
final int bondedCount = listBondedValues.size() + 1; // 1 for the title
final int availableCount = listValues.isEmpty() ? 2 : listValues.size() + 1; // 1 for title, 1 for empty text
if (bondedCount == 1)
return availableCount;
return bondedCount + availableCount;
}
@Override
public Object getItem(int position) {
final int bondedCount = mListBondedValues.size() + 1; // 1 for the title
if (mListBondedValues.isEmpty()) {
public Object getItem(final int position) {
final int bondedCount = listBondedValues.size() + 1; // 1 for the title
if (listBondedValues.isEmpty()) {
if (position == 0)
return R.string.scanner_subtitle_not_bonded;
else
return mListValues.get(position - 1);
return listValues.get(position - 1);
} else {
if (position == 0)
return R.string.scanner_subtitle_bonded;
if (position < bondedCount)
return mListBondedValues.get(position - 1);
return listBondedValues.get(position - 1);
if (position == bondedCount)
return R.string.scanner_subtitle_not_bonded;
return mListValues.get(position - bondedCount - 1);
return listValues.get(position - bondedCount - 1);
}
}
@@ -136,32 +134,32 @@ public class DeviceListAdapter extends BaseAdapter {
}
@Override
public boolean isEnabled(int position) {
public boolean isEnabled(final int position) {
return getItemViewType(position) == TYPE_ITEM;
}
@Override
public int getItemViewType(int position) {
public int getItemViewType(final int position) {
if (position == 0)
return TYPE_TITLE;
if (!mListBondedValues.isEmpty() && position == mListBondedValues.size() + 1)
if (!listBondedValues.isEmpty() && position == listBondedValues.size() + 1)
return TYPE_TITLE;
if (position == getCount() - 1 && mListValues.isEmpty())
if (position == getCount() - 1 && listValues.isEmpty())
return TYPE_EMPTY;
return TYPE_ITEM;
}
@Override
public long getItemId(int position) {
public long getItemId(final int position) {
return position;
}
@Override
public View getView(int position, View oldView, ViewGroup parent) {
final LayoutInflater inflater = LayoutInflater.from(mContext);
public View getView(final int position, @Nullable final View oldView, @NonNull final ViewGroup parent) {
final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
final int type = getItemViewType(position);
View view = oldView;
@@ -191,7 +189,7 @@ public class DeviceListAdapter extends BaseAdapter {
final ExtendedBluetoothDevice device = (ExtendedBluetoothDevice) getItem(position);
final ViewHolder holder = (ViewHolder) view.getTag();
final String name = device.name;
holder.name.setText(name != null ? name : mContext.getString(R.string.not_available));
holder.name.setText(name != null ? name : parent.getContext().getString(R.string.not_available));
holder.address.setText(device.device.getAddress());
if (!device.isBonded || device.rssi != ExtendedBluetoothDevice.NO_RSSI) {
final int rssiPercent = (int) (100.0f * (127.0f + device.rssi) / (127.0f + 20.0f));

View File

@@ -23,8 +23,10 @@ package no.nordicsemi.android.nrftoolbox.scanner;
import android.bluetooth.BluetoothDevice;
import androidx.annotation.NonNull;
import no.nordicsemi.android.support.v18.scanner.ScanResult;
@SuppressWarnings("WeakerAccess")
public class ExtendedBluetoothDevice {
/* package */ static final int NO_RSSI = -1000;
public final BluetoothDevice device;
@@ -33,21 +35,21 @@ public class ExtendedBluetoothDevice {
public int rssi;
public boolean isBonded;
public ExtendedBluetoothDevice(final ScanResult scanResult) {
public ExtendedBluetoothDevice(@NonNull final ScanResult scanResult) {
this.device = scanResult.getDevice();
this.name = scanResult.getScanRecord() != null ? scanResult.getScanRecord().getDeviceName() : null;
this.rssi = scanResult.getRssi();
this.isBonded = false;
}
public ExtendedBluetoothDevice(final BluetoothDevice device) {
public ExtendedBluetoothDevice(@NonNull final BluetoothDevice device) {
this.device = device;
this.name = device.getName();
this.rssi = NO_RSSI;
this.isBonded = true;
}
public boolean matches(final ScanResult scanResult) {
public boolean matches(@NonNull final ScanResult scanResult) {
return device.getAddress().equals(scanResult.getDevice().getAddress());
}
}

View File

@@ -33,6 +33,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.ParcelUuid;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.DialogFragment;
import androidx.core.content.ContextCompat;
@@ -70,17 +71,17 @@ public class ScannerFragment extends DialogFragment {
private final static int REQUEST_PERMISSION_REQ_CODE = 34; // any 8-bit number
private BluetoothAdapter mBluetoothAdapter;
private OnDeviceSelectedListener mListener;
private DeviceListAdapter mAdapter;
private final Handler mHandler = new Handler();
private Button mScanButton;
private BluetoothAdapter bluetoothAdapter;
private OnDeviceSelectedListener listener;
private DeviceListAdapter adapter;
private final Handler handler = new Handler();
private Button scanButton;
private View mPermissionRationale;
private View permissionRationale;
private ParcelUuid mUuid;
private ParcelUuid uuid;
private boolean mIsScanning = false;
private boolean scanning = false;
public static ScannerFragment getInstance(final UUID uuid) {
final ScannerFragment fragment = new ScannerFragment();
@@ -106,7 +107,7 @@ public class ScannerFragment extends DialogFragment {
* always returns <code>null</code>, i.e. Sony Xperia Z1 (C6903) with Android 4.3.
* The name has to be parsed manually form the Advertisement packet.
*/
void onDeviceSelected(final BluetoothDevice device, final String name);
void onDeviceSelected(@NonNull final BluetoothDevice device, @Nullable final String name);
/**
* Fired when scanner dialog has been cancelled without selecting a device.
@@ -118,10 +119,10 @@ public class ScannerFragment extends DialogFragment {
* This will make sure that {@link OnDeviceSelectedListener} interface is implemented by activity.
*/
@Override
public void onAttach(final Context context) {
public void onAttach(@NonNull final Context context) {
super.onAttach(context);
try {
this.mListener = (OnDeviceSelectedListener) context;
this.listener = (OnDeviceSelectedListener) context;
} catch (final ClassCastException e) {
throw new ClassCastException(context.toString() + " must implement OnDeviceSelectedListener");
}
@@ -133,12 +134,12 @@ public class ScannerFragment extends DialogFragment {
final Bundle args = getArguments();
if (args != null && args.containsKey(PARAM_UUID)) {
mUuid = args.getParcelable(PARAM_UUID);
uuid = args.getParcelable(PARAM_UUID);
}
final BluetoothManager manager = (BluetoothManager) requireContext().getSystemService(Context.BLUETOOTH_SERVICE);
if (manager != null) {
mBluetoothAdapter = manager.getAdapter();
bluetoothAdapter = manager.getAdapter();
}
}
@@ -152,27 +153,28 @@ public class ScannerFragment extends DialogFragment {
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
final View dialogView = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_device_selection, null);
final View dialogView = LayoutInflater.from(requireContext())
.inflate(R.layout.fragment_device_selection, null);
final ListView listview = dialogView.findViewById(android.R.id.list);
listview.setEmptyView(dialogView.findViewById(android.R.id.empty));
listview.setAdapter(mAdapter = new DeviceListAdapter(getActivity()));
listview.setAdapter(adapter = new DeviceListAdapter());
builder.setTitle(R.string.scanner_title);
final AlertDialog dialog = builder.setView(dialogView).create();
listview.setOnItemClickListener((parent, view, position, id) -> {
stopScan();
dialog.dismiss();
final ExtendedBluetoothDevice d = (ExtendedBluetoothDevice) mAdapter.getItem(position);
mListener.onDeviceSelected(d.device, d.name);
final ExtendedBluetoothDevice d = (ExtendedBluetoothDevice) adapter.getItem(position);
listener.onDeviceSelected(d.device, d.name);
});
mPermissionRationale = dialogView.findViewById(R.id.permission_rationale); // this is not null only on API23+
permissionRationale = dialogView.findViewById(R.id.permission_rationale); // this is not null only on API23+
mScanButton = dialogView.findViewById(R.id.action_cancel);
mScanButton.setOnClickListener(v -> {
scanButton = dialogView.findViewById(R.id.action_cancel);
scanButton.setOnClickListener(v -> {
if (v.getId() == R.id.action_cancel) {
if (mIsScanning) {
if (scanning) {
dialog.cancel();
} else {
startScan();
@@ -187,10 +189,10 @@ public class ScannerFragment extends DialogFragment {
}
@Override
public void onCancel(DialogInterface dialog) {
public void onCancel(@NonNull DialogInterface dialog) {
super.onCancel(dialog);
mListener.onDialogCanceled();
listener.onDialogCanceled();
}
@Override
@@ -201,7 +203,7 @@ public class ScannerFragment extends DialogFragment {
// We have been granted the Manifest.permission.ACCESS_FINE_LOCATION permission. Now we may proceed with scanning.
startScan();
} else {
mPermissionRationale.setVisibility(View.VISIBLE);
permissionRationale.setVisibility(View.VISIBLE);
Toast.makeText(getActivity(), R.string.no_required_permission, Toast.LENGTH_SHORT).show();
}
break;
@@ -210,7 +212,7 @@ public class ScannerFragment extends DialogFragment {
}
/**
* Scan for 5 seconds and then stop scanning when a BluetoothLE device is found then mLEScanCallback
* Scan for 5 seconds and then stop scanning when a BluetoothLE device is found then lEScanCallback
* is activated This will perform regular scan for custom BLE Service UUID and then filter out.
* using class ScannerServiceParser
*/
@@ -220,8 +222,8 @@ public class ScannerFragment extends DialogFragment {
// On API older than Marshmallow the following code does nothing.
if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// When user pressed Deny and still wants to use this functionality, show the rationale
if (ActivityCompat.shouldShowRequestPermissionRationale(requireActivity(), Manifest.permission.ACCESS_FINE_LOCATION) && mPermissionRationale.getVisibility() == View.GONE) {
mPermissionRationale.setVisibility(View.VISIBLE);
if (ActivityCompat.shouldShowRequestPermissionRationale(requireActivity(), Manifest.permission.ACCESS_FINE_LOCATION) && permissionRationale.getVisibility() == View.GONE) {
permissionRationale.setVisibility(View.VISIBLE);
return;
}
@@ -230,23 +232,23 @@ public class ScannerFragment extends DialogFragment {
}
// Hide the rationale message, we don't need it anymore.
if (mPermissionRationale != null)
mPermissionRationale.setVisibility(View.GONE);
if (permissionRationale != null)
permissionRationale.setVisibility(View.GONE);
mAdapter.clearDevices();
mScanButton.setText(R.string.scanner_action_cancel);
adapter.clearDevices();
scanButton.setText(R.string.scanner_action_cancel);
final BluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();
final ScanSettings settings = new ScanSettings.Builder()
.setLegacy(false)
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).setReportDelay(1000).setUseHardwareBatchingIfSupported(false).build();
final List<ScanFilter> filters = new ArrayList<>();
filters.add(new ScanFilter.Builder().setServiceUuid(mUuid).build());
filters.add(new ScanFilter.Builder().setServiceUuid(uuid).build());
scanner.startScan(filters, settings, scanCallback);
mIsScanning = true;
mHandler.postDelayed(() -> {
if (mIsScanning) {
scanning = true;
handler.postDelayed(() -> {
if (scanning) {
stopScan();
}
}, SCAN_DURATION);
@@ -256,25 +258,25 @@ public class ScannerFragment extends DialogFragment {
* Stop scan if user tap Cancel button
*/
private void stopScan() {
if (mIsScanning) {
mScanButton.setText(R.string.scanner_action_scan);
if (scanning) {
scanButton.setText(R.string.scanner_action_scan);
final BluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();
scanner.stopScan(scanCallback);
mIsScanning = false;
scanning = false;
}
}
private ScanCallback scanCallback = new ScanCallback() {
@Override
public void onScanResult(final int callbackType, final ScanResult result) {
public void onScanResult(final int callbackType, @NonNull final ScanResult result) {
// do nothing
}
@Override
public void onBatchScanResults(final List<ScanResult> results) {
mAdapter.update(results);
public void onBatchScanResults(@NonNull final List<ScanResult> results) {
adapter.update(results);
}
@Override
@@ -284,7 +286,7 @@ public class ScannerFragment extends DialogFragment {
};
private void addBoundDevices() {
final Set<BluetoothDevice> devices = mBluetoothAdapter.getBondedDevices();
mAdapter.addBondedDevices(devices);
final Set<BluetoothDevice> devices = bluetoothAdapter.getBondedDevices();
adapter.addBondedDevices(devices);
}
}

View File

@@ -47,8 +47,8 @@ public class TemplateActivity extends BleProfileServiceReadyActivity<TemplateSer
private final String TAG = "TemplateActivity";
// TODO change view references to match your need
private TextView mValueView;
private TextView mBatteryLevelView;
private TextView valueView;
private TextView batteryLevelView;
@Override
protected void onCreateView(final Bundle savedInstanceState) {
@@ -59,8 +59,8 @@ public class TemplateActivity extends BleProfileServiceReadyActivity<TemplateSer
private void setGUI() {
// TODO assign your views to fields
mValueView = findViewById(R.id.value);
mBatteryLevelView = findViewById(R.id.battery);
valueView = findViewById(R.id.value);
batteryLevelView = findViewById(R.id.battery);
findViewById(R.id.action_set_name).setOnClickListener(v -> {
if (isDeviceConnected()) {
@@ -71,20 +71,20 @@ public class TemplateActivity extends BleProfileServiceReadyActivity<TemplateSer
@Override
protected void onInitialize(final Bundle savedInstanceState) {
LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, makeIntentFilter());
LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, makeIntentFilter());
}
@Override
protected void onDestroy() {
super.onDestroy();
LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver);
LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver);
}
@Override
protected void setDefaultUI() {
// TODO clear your UI
mValueView.setText(R.string.not_available_value);
mBatteryLevelView.setText(R.string.not_available);
valueView.setText(R.string.not_available_value);
batteryLevelView.setText(R.string.not_available);
}
@Override
@@ -142,29 +142,29 @@ public class TemplateActivity extends BleProfileServiceReadyActivity<TemplateSer
}
@Override
public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) {
public void onServicesDiscovered(@NonNull final BluetoothDevice device, final boolean optionalServicesFound) {
// this may notify user or show some views
}
@Override
public void onDeviceDisconnected(final BluetoothDevice device) {
public void onDeviceDisconnected(@NonNull final BluetoothDevice device) {
super.onDeviceDisconnected(device);
mBatteryLevelView.setText(R.string.not_available);
batteryLevelView.setText(R.string.not_available);
}
// Handling updates from the device
@SuppressWarnings("unused")
private void setValueOnView(@NonNull final BluetoothDevice device, final int value) {
// TODO assign the value to a view
mValueView.setText(String.valueOf(value));
valueView.setText(String.valueOf(value));
}
@SuppressWarnings("unused")
public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int value) {
mBatteryLevelView.setText(getString(R.string.battery, value));
batteryLevelView.setText(getString(R.string.battery, value));
}
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
final String action = intent.getAction();

View File

@@ -69,7 +69,7 @@ public class TemplateManager extends BatteryManager<TemplateManagerCallbacks> {
private static final UUID WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00002A00-0000-1000-8000-00805f9b34fb"); // Device Name
// TODO Add more services and characteristics references.
private BluetoothGattCharacteristic mRequiredCharacteristic, mDeviceNameCharacteristic, mOptionalCharacteristic;
private BluetoothGattCharacteristic requiredCharacteristic, deviceNameCharacteristic, optionalCharacteristic;
public TemplateManager(final Context context) {
super(context);
@@ -78,14 +78,14 @@ public class TemplateManager extends BatteryManager<TemplateManagerCallbacks> {
@NonNull
@Override
protected BatteryManagerGattCallback getGattCallback() {
return mGattCallback;
return gattCallback;
}
/**
* BluetoothGatt callbacks for connection/disconnection, service discovery,
* receiving indication, etc.
*/
private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() {
private final BatteryManagerGattCallback gattCallback = new BatteryManagerGattCallback() {
@Override
protected void initialize() {
@@ -111,7 +111,7 @@ public class TemplateManager extends BatteryManager<TemplateManagerCallbacks> {
.enqueue();
// Set notification callback
setNotificationCallback(mRequiredCharacteristic)
setNotificationCallback(requiredCharacteristic)
// This callback will be called each time the notification is received
.with(new TemplateDataCallback() {
@Override
@@ -123,7 +123,7 @@ public class TemplateManager extends BatteryManager<TemplateManagerCallbacks> {
@Override
public void onSampleValueReceived(@NonNull final BluetoothDevice device, final int value) {
// Let's lass received data to the service
mCallbacks.onSampleValueReceived(device, value);
callbacks.onSampleValueReceived(device, value);
}
@Override
@@ -133,7 +133,7 @@ public class TemplateManager extends BatteryManager<TemplateManagerCallbacks> {
});
// Enable notifications
enableNotifications(mRequiredCharacteristic)
enableNotifications(requiredCharacteristic)
// Method called after the data were sent (data will contain 0x0100 in this case)
.with((device, data) -> log(Log.DEBUG, "Data sent: " + data))
// Method called when the request finished successfully. This will be called after .with(..) callback
@@ -149,13 +149,13 @@ public class TemplateManager extends BatteryManager<TemplateManagerCallbacks> {
// It should return true if all has been discovered (that is that device is supported).
final BluetoothGattService service = gatt.getService(SERVICE_UUID);
if (service != null) {
mRequiredCharacteristic = service.getCharacteristic(MEASUREMENT_CHARACTERISTIC_UUID);
requiredCharacteristic = service.getCharacteristic(MEASUREMENT_CHARACTERISTIC_UUID);
}
final BluetoothGattService otherService = gatt.getService(OTHER_SERVICE_UUID);
if (otherService != null) {
mDeviceNameCharacteristic = otherService.getCharacteristic(WRITABLE_CHARACTERISTIC_UUID);
deviceNameCharacteristic = otherService.getCharacteristic(WRITABLE_CHARACTERISTIC_UUID);
}
return mRequiredCharacteristic != null && mDeviceNameCharacteristic != null;
return requiredCharacteristic != null && deviceNameCharacteristic != null;
}
@Override
@@ -166,9 +166,9 @@ public class TemplateManager extends BatteryManager<TemplateManagerCallbacks> {
// TODO If there are some optional characteristics, initialize them there.
final BluetoothGattService service = gatt.getService(SERVICE_UUID);
if (service != null) {
mOptionalCharacteristic = service.getCharacteristic(READABLE_CHARACTERISTIC_UUID);
optionalCharacteristic = service.getCharacteristic(READABLE_CHARACTERISTIC_UUID);
}
return mOptionalCharacteristic != null;
return optionalCharacteristic != null;
}
@Override
@@ -177,9 +177,9 @@ public class TemplateManager extends BatteryManager<TemplateManagerCallbacks> {
super.onDeviceDisconnected();
// TODO Release references to your characteristics.
mRequiredCharacteristic = null;
mDeviceNameCharacteristic = null;
mOptionalCharacteristic = null;
requiredCharacteristic = null;
deviceNameCharacteristic = null;
optionalCharacteristic = null;
}
@Override
@@ -192,7 +192,7 @@ public class TemplateManager extends BatteryManager<TemplateManagerCallbacks> {
// Device is ready, let's read something here. Usually there is nothing else to be done
// here, as all had been done during initialization.
readCharacteristic(mOptionalCharacteristic)
readCharacteristic(optionalCharacteristic)
.with((device, data) -> {
// Characteristic value has been read
// Let's do some magic with it.
@@ -217,7 +217,7 @@ public class TemplateManager extends BatteryManager<TemplateManagerCallbacks> {
void performAction(final String parameter) {
log(Log.VERBOSE, "Changing device name to \"" + parameter + "\"");
// Write some data to the characteristic.
writeCharacteristic(mDeviceNameCharacteristic, Data.from(parameter))
writeCharacteristic(deviceNameCharacteristic, Data.from(parameter))
// If data are longer than MTU-3, they will be chunked into multiple packets.
// Check out other split options, with .split(...).
.split()

View File

@@ -55,9 +55,9 @@ public class TemplateService extends BleProfileService implements TemplateManage
private final static int OPEN_ACTIVITY_REQ = 0;
private final static int DISCONNECT_REQ = 1;
private TemplateManager mManager;
private TemplateManager manager;
private final LocalBinder mBinder = new TemplateBinder();
private final LocalBinder binder = new TemplateBinder();
/**
* This local binder is an interface for the bound activity to operate with the sensor.
@@ -70,19 +70,19 @@ public class TemplateService extends BleProfileService implements TemplateManage
*
* @param parameter some parameter.
*/
public void performAction(final String parameter) {
mManager.performAction(parameter);
void performAction(final String parameter) {
manager.performAction(parameter);
}
}
@Override
protected LocalBinder getBinder() {
return mBinder;
return binder;
}
@Override
protected LoggableBleManager<TemplateManagerCallbacks> initializeManager() {
return mManager = new TemplateManager(this);
return manager = new TemplateManager(this);
}
@Override
@@ -91,14 +91,14 @@ public class TemplateService extends BleProfileService implements TemplateManage
final IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_DISCONNECT);
registerReceiver(mDisconnectActionBroadcastReceiver, filter);
registerReceiver(disconnectActionBroadcastReceiver, filter);
}
@Override
public void onDestroy() {
// when user has disconnected from the sensor, we have to cancel the notification that we've created some milliseconds before using unbindService
stopForegroundService();
unregisterReceiver(mDisconnectActionBroadcastReceiver);
unregisterReceiver(disconnectActionBroadcastReceiver);
super.onDestroy();
}
@@ -120,7 +120,7 @@ public class TemplateService extends BleProfileService implements TemplateManage
broadcast.putExtra(EXTRA_DATA, value);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
if (!mBound) {
if (!bound) {
// Here we may update the notification to display the current value.
// TODO modify the notification here
}
@@ -166,6 +166,7 @@ public class TemplateService extends BleProfileService implements TemplateManage
* f.e. <code>&lt;string name="name"&gt;%s is connected&lt;/string&gt;</code>
* @param defaults signals that will be used to notify the user
*/
@SuppressWarnings("SameParameterValue")
private Notification createNotification(final int messageResId, final int defaults) {
final Intent parentIntent = new Intent(this, FeaturesActivity.class);
parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -197,7 +198,7 @@ public class TemplateService extends BleProfileService implements TemplateManage
/**
* This broadcast receiver listens for {@link #ACTION_DISCONNECT} that may be fired by pressing Disconnect action button on the notification.
*/
private final BroadcastReceiver mDisconnectActionBroadcastReceiver = new BroadcastReceiver() {
private final BroadcastReceiver disconnectActionBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
Logger.i(getLogSession(), "[Notification] Disconnect action pressed");

View File

@@ -115,28 +115,28 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
private final static int SELECT_FILE_REQ = 2678; // random
private final static int PERMISSION_REQ = 24; // random, 8-bit
UARTConfigurationSynchronizer mWearableSynchronizer;
UARTConfigurationSynchronizer wearableSynchronizer;
/** The current configuration. */
private UartConfiguration mConfiguration;
private DatabaseHelper mDatabaseHelper;
private SharedPreferences mPreferences;
private UARTConfigurationsAdapter mConfigurationsAdapter;
private ClosableSpinner mConfigurationSpinner;
private SlidingPaneLayout mSlider;
private View mContainer;
private UARTService.UARTBinder mServiceBinder;
private ConfigurationListener mConfigurationListener;
private boolean mEditMode;
private UartConfiguration configuration;
private DatabaseHelper databaseHelper;
private SharedPreferences preferences;
private UARTConfigurationsAdapter configurationsAdapter;
private ClosableSpinner configurationSpinner;
private SlidingPaneLayout slider;
private View container;
private UARTService.UARTBinder serviceBinder;
private ConfigurationListener configurationListener;
private boolean editMode;
public interface ConfigurationListener {
void onConfigurationModified();
void onConfigurationChanged(final UartConfiguration configuration);
void onConfigurationChanged(@NonNull final UartConfiguration configuration);
void setEditMode(final boolean editMode);
}
public void setConfigurationListener(final ConfigurationListener listener) {
mConfigurationListener = listener;
configurationListener = listener;
}
@Override
@@ -161,23 +161,23 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
@Override
protected void onServiceBound(final UARTService.UARTBinder binder) {
mServiceBinder = binder;
serviceBinder = binder;
}
@Override
protected void onServiceUnbound() {
mServiceBinder = null;
serviceBinder = null;
}
@Override
protected void onInitialize(final Bundle savedInstanceState) {
mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
mDatabaseHelper = new DatabaseHelper(this);
ensureFirstConfiguration(mDatabaseHelper);
mConfigurationsAdapter = new UARTConfigurationsAdapter(this, this, mDatabaseHelper.getConfigurationsNames());
preferences = PreferenceManager.getDefaultSharedPreferences(this);
databaseHelper = new DatabaseHelper(this);
ensureFirstConfiguration(databaseHelper);
configurationsAdapter = new UARTConfigurationsAdapter(this, this, databaseHelper.getConfigurationsNames());
// Initialize Wearable synchronizer
mWearableSynchronizer = UARTConfigurationSynchronizer.from(this, this);
wearableSynchronizer = UARTConfigurationSynchronizer.from(this, this);
}
/**
@@ -186,12 +186,12 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
@Override
public void onConnected(final Bundle bundle) {
// Ensure the Wearable API was connected
if (!mWearableSynchronizer.hasConnectedApi())
if (!wearableSynchronizer.hasConnectedApi())
return;
if (!mPreferences.getBoolean(PREFS_WEAR_SYNCED, false)) {
if (!preferences.getBoolean(PREFS_WEAR_SYNCED, false)) {
new Thread(() -> {
final Cursor cursor = mDatabaseHelper.getConfigurations();
final Cursor cursor = databaseHelper.getConfigurations();
try {
while (cursor.moveToNext()) {
final long id = cursor.getLong(0 /* _ID */);
@@ -200,12 +200,12 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
final Format format = new Format(new HyphenStyle());
final Serializer serializer = new Persister(format);
final UartConfiguration configuration = serializer.read(UartConfiguration.class, xml);
mWearableSynchronizer.onConfigurationAddedOrEdited(id, configuration).await();
wearableSynchronizer.onConfigurationAddedOrEdited(id, configuration).await();
} catch (final Exception e) {
Log.w(TAG, "Deserializing configuration with id " + id + " failed", e);
}
}
mPreferences.edit().putBoolean(PREFS_WEAR_SYNCED, true).apply();
preferences.edit().putBoolean(PREFS_WEAR_SYNCED, true).apply();
} finally {
cursor.close();
}
@@ -225,16 +225,16 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
@Override
protected void onDestroy() {
super.onDestroy();
mWearableSynchronizer.close();
wearableSynchronizer.close();
}
@Override
protected void onCreateView(final Bundle savedInstanceState) {
setContentView(R.layout.activity_feature_uart);
mContainer = findViewById(R.id.container);
container = findViewById(R.id.container);
// Setup the sliding pane if it exists
final SlidingPaneLayout slidingPane = mSlider = findViewById(R.id.sliding_pane);
final SlidingPaneLayout slidingPane = slider = findViewById(R.id.sliding_pane);
if (slidingPane != null) {
slidingPane.setSliderFadeColor(Color.TRANSPARENT);
slidingPane.setShadowResourceLeft(R.drawable.shadow_r);
@@ -253,34 +253,34 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
protected void onViewCreated(final Bundle savedInstanceState) {
getSupportActionBar().setDisplayShowTitleEnabled(false);
final ClosableSpinner configurationSpinner = mConfigurationSpinner = findViewById(R.id.toolbar_spinner);
final ClosableSpinner configurationSpinner = this.configurationSpinner = findViewById(R.id.toolbar_spinner);
configurationSpinner.setOnItemSelectedListener(this);
configurationSpinner.setAdapter(mConfigurationsAdapter);
configurationSpinner.setSelection(mConfigurationsAdapter.getItemPosition(mPreferences.getLong(PREFS_CONFIGURATION, 0)));
configurationSpinner.setAdapter(configurationsAdapter);
configurationSpinner.setSelection(configurationsAdapter.getItemPosition(preferences.getLong(PREFS_CONFIGURATION, 0)));
}
@Override
protected void onRestoreInstanceState(final @NonNull Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mEditMode = savedInstanceState.getBoolean(SIS_EDIT_MODE);
setEditMode(mEditMode, false);
editMode = savedInstanceState.getBoolean(SIS_EDIT_MODE);
setEditMode(editMode, false);
}
@Override
public void onSaveInstanceState(final Bundle outState) {
public void onSaveInstanceState(@NonNull final Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(SIS_EDIT_MODE, mEditMode);
outState.putBoolean(SIS_EDIT_MODE, editMode);
}
@Override
public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) {
public void onServicesDiscovered(@NonNull final BluetoothDevice device, final boolean optionalServicesFound) {
// do nothing
}
@Override
public void onDeviceSelected(final BluetoothDevice device, final String name) {
public void onDeviceSelected(@NonNull final BluetoothDevice device, final String name) {
// The super method starts the service
super.onDeviceSelected(device, name);
@@ -306,8 +306,8 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
@Override
public void send(final String text) {
if (mServiceBinder != null)
mServiceBinder.send(text);
if (serviceBinder != null)
serviceBinder.send(text);
}
public void setEditMode(final boolean editMode) {
@@ -317,11 +317,11 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
@Override
public void onBackPressed() {
if (mSlider != null && mSlider.isOpen()) {
mSlider.closePane();
if (slider != null && slider.isOpen()) {
slider.closePane();
return;
}
if (mEditMode) {
if (editMode) {
setEditMode(false);
return;
}
@@ -331,31 +331,31 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
@Override
public boolean onCreateOptionsMenu(final Menu menu) {
getMenuInflater().inflate(R.menu.uart_menu_configurations, menu);
getMenuInflater().inflate(mEditMode ? R.menu.uart_menu_config : R.menu.uart_menu, menu);
getMenuInflater().inflate(editMode ? R.menu.uart_menu_config : R.menu.uart_menu, menu);
final int configurationsCount = mDatabaseHelper.getConfigurationsCount();
final int configurationsCount = databaseHelper.getConfigurationsCount();
menu.findItem(R.id.action_remove).setVisible(configurationsCount > 1);
return super.onCreateOptionsMenu(menu);
}
@Override
protected boolean onOptionsItemSelected(int itemId) {
final String name = mConfiguration.getName();
final String name = configuration.getName();
switch (itemId) {
case R.id.action_configure:
setEditMode(!mEditMode);
setEditMode(!editMode);
return true;
case R.id.action_show_log:
mSlider.openPane();
slider.openPane();
return true;
case R.id.action_share: {
final String xml = mDatabaseHelper.getConfiguration(mConfigurationSpinner.getSelectedItemId());
final String xml = databaseHelper.getConfiguration(configurationSpinner.getSelectedItemId());
final Intent intent = new Intent(Intent.ACTION_SEND);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setType("text/xml");
intent.putExtra(Intent.EXTRA_TEXT, xml);
intent.putExtra(Intent.EXTRA_SUBJECT, mConfiguration.getName());
intent.putExtra(Intent.EXTRA_SUBJECT, configuration.getName());
try {
startActivity(intent);
} catch (final ActivityNotFoundException e) {
@@ -384,17 +384,17 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
return true;
}
case R.id.action_remove: {
mDatabaseHelper.removeDeletedServerConfigurations(); // just to be sure nothing has left
final UartConfiguration removedConfiguration = mConfiguration;
final long id = mDatabaseHelper.deleteConfiguration(name);
databaseHelper.removeDeletedServerConfigurations(); // just to be sure nothing has left
final UartConfiguration removedConfiguration = configuration;
final long id = databaseHelper.deleteConfiguration(name);
if (id >= 0)
mWearableSynchronizer.onConfigurationDeleted(id);
wearableSynchronizer.onConfigurationDeleted(id);
refreshConfigurations();
final Snackbar snackbar = Snackbar.make(mContainer, R.string.uart_configuration_deleted, Snackbar.LENGTH_INDEFINITE).setAction(R.string.uart_action_undo, v -> {
final long id1 = mDatabaseHelper.restoreDeletedServerConfiguration(name);
final Snackbar snackbar = Snackbar.make(container, R.string.uart_configuration_deleted, Snackbar.LENGTH_INDEFINITE).setAction(R.string.uart_action_undo, v -> {
final long id1 = databaseHelper.restoreDeletedServerConfiguration(name);
if (id1 >= 0)
mWearableSynchronizer.onConfigurationAddedOrEdited(id1, removedConfiguration);
wearableSynchronizer.onConfigurationAddedOrEdited(id1, removedConfiguration);
refreshConfigurations();
});
snackbar.setDuration(5000); // This is not an error
@@ -425,11 +425,11 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
public void onItemSelected(final AdapterView<?> parent, final View view, final int position, final long id) {
if (position > 0) { // FIXME this is called twice after rotation.
try {
final String xml = mDatabaseHelper.getConfiguration(id);
final String xml = databaseHelper.getConfiguration(id);
final Format format = new Format(new HyphenStyle());
final Serializer serializer = new Persister(format);
mConfiguration = serializer.read(UartConfiguration.class, xml);
mConfigurationListener.onConfigurationChanged(mConfiguration);
configuration = serializer.read(UartConfiguration.class, xml);
configurationListener.onConfigurationChanged(configuration);
} catch (final Exception e) {
Log.e(TAG, "Selecting configuration failed", e);
@@ -441,11 +441,11 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
else
message = "Unknown error";
final String msg = message;
Snackbar.make(mContainer, R.string.uart_configuration_loading_failed, Snackbar.LENGTH_INDEFINITE).setAction(R.string.uart_action_details, v -> new AlertDialog.Builder(UARTActivity.this).setMessage(msg).setTitle(R.string.uart_action_details).setPositiveButton(R.string.ok, null).show()).show();
Snackbar.make(container, R.string.uart_configuration_loading_failed, Snackbar.LENGTH_INDEFINITE).setAction(R.string.uart_action_details, v -> new AlertDialog.Builder(UARTActivity.this).setMessage(msg).setTitle(R.string.uart_action_details).setPositiveButton(R.string.ok, null).show()).show();
return;
}
mPreferences.edit().putLong(PREFS_CONFIGURATION, id).apply();
preferences.edit().putLong(PREFS_CONFIGURATION, id).apply();
}
}
@@ -457,7 +457,7 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
@Override
public void onNewConfigurationClick() {
// No item has been selected. We must close the spinner manually.
mConfigurationSpinner.close();
configurationSpinner.close();
// Open the dialog
final DialogFragment fragment = UARTNewConfigurationDialogFragment.getInstance(null, false);
@@ -469,7 +469,7 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
@Override
public void onImportClick() {
// No item has been selected. We must close the spinner manually.
mConfigurationSpinner.close();
configurationSpinner.close();
final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("text/xml");
@@ -542,25 +542,25 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
}
public void onCommandChanged(final int index, final String message, final boolean active, final int eol, final int iconIndex) {
final Command command = mConfiguration.getCommands()[index];
final Command command = configuration.getCommands()[index];
command.setCommand(message);
command.setActive(active);
command.setEol(eol);
command.setIconIndex(iconIndex);
mConfigurationListener.onConfigurationModified();
configurationListener.onConfigurationModified();
saveConfiguration();
}
@Override
public void onNewConfiguration(final String name, final boolean duplicate) {
final boolean exists = mDatabaseHelper.configurationExists(name);
final boolean exists = databaseHelper.configurationExists(name);
if (exists) {
Toast.makeText(this, R.string.uart_configuration_name_already_taken, Toast.LENGTH_LONG).show();
return;
}
UartConfiguration configuration = mConfiguration;
UartConfiguration configuration = this.configuration;
if (!duplicate)
configuration = new UartConfiguration();
configuration.setName(name);
@@ -573,10 +573,10 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
serializer.write(configuration, writer);
final String xml = writer.toString();
final long id = mDatabaseHelper.addConfiguration(name, xml);
mWearableSynchronizer.onConfigurationAddedOrEdited(id, configuration);
final long id = databaseHelper.addConfiguration(name, xml);
wearableSynchronizer.onConfigurationAddedOrEdited(id, configuration);
refreshConfigurations();
selectConfiguration(mConfigurationsAdapter.getItemPosition(id));
selectConfiguration(configurationsAdapter.getItemPosition(id));
} catch (final Exception e) {
Log.e(TAG, "Error while creating a new configuration", e);
}
@@ -584,25 +584,25 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
@Override
public void onRenameConfiguration(final String newName) {
final boolean exists = mDatabaseHelper.configurationExists(newName);
final boolean exists = databaseHelper.configurationExists(newName);
if (exists) {
Toast.makeText(this, R.string.uart_configuration_name_already_taken, Toast.LENGTH_LONG).show();
return;
}
final String oldName = mConfiguration.getName();
mConfiguration.setName(newName);
final String oldName = configuration.getName();
configuration.setName(newName);
try {
final Format format = new Format(new HyphenStyle());
final Strategy strategy = new VisitorStrategy(new CommentVisitor());
final Serializer serializer = new Persister(strategy, format);
final StringWriter writer = new StringWriter();
serializer.write(mConfiguration, writer);
serializer.write(configuration, writer);
final String xml = writer.toString();
mDatabaseHelper.renameConfiguration(oldName, newName, xml);
mWearableSynchronizer.onConfigurationAddedOrEdited(mPreferences.getLong(PREFS_CONFIGURATION, 0), mConfiguration);
databaseHelper.renameConfiguration(oldName, newName, xml);
wearableSynchronizer.onConfigurationAddedOrEdited(preferences.getLong(PREFS_CONFIGURATION, 0), configuration);
refreshConfigurations();
} catch (final Exception e) {
Log.e(TAG, "Error while renaming configuration", e);
@@ -610,13 +610,13 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
}
private void refreshConfigurations() {
mConfigurationsAdapter.swapCursor(mDatabaseHelper.getConfigurationsNames());
mConfigurationsAdapter.notifyDataSetChanged();
configurationsAdapter.swapCursor(databaseHelper.getConfigurationsNames());
configurationsAdapter.notifyDataSetChanged();
invalidateOptionsMenu();
}
private void selectConfiguration(final int position) {
mConfigurationSpinner.setSelection(position);
configurationSpinner.setSelection(position);
}
/**
@@ -629,8 +629,8 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
*/
@SuppressLint("NewApi")
private void setEditMode(final boolean editMode, final boolean change) {
mEditMode = editMode;
mConfigurationListener.setEditMode(editMode);
this.editMode = editMode;
configurationListener.setEditMode(editMode);
if (!change) {
final ColorDrawable color = new ColorDrawable();
int darkColor = 0;
@@ -664,8 +664,8 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
anim.start();
}
if (mSlider != null && editMode) {
mSlider.closePane();
if (slider != null && editMode) {
slider.closePane();
}
}
}
@@ -674,7 +674,7 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
* Saves the given configuration in the database.
*/
private void saveConfiguration() {
final UartConfiguration configuration = mConfiguration;
final UartConfiguration configuration = this.configuration;
try {
final Format format = new Format(new HyphenStyle());
final Strategy strategy = new VisitorStrategy(new CommentVisitor());
@@ -683,8 +683,8 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
serializer.write(configuration, writer);
final String xml = writer.toString();
mDatabaseHelper.updateConfiguration(configuration.getName(), xml);
mWearableSynchronizer.onConfigurationAddedOrEdited(mPreferences.getLong(PREFS_CONFIGURATION, 0), configuration);
databaseHelper.updateConfiguration(configuration.getName(), xml);
wearableSynchronizer.onConfigurationAddedOrEdited(preferences.getLong(PREFS_CONFIGURATION, 0), configuration);
} catch (final Exception e) {
Log.e(TAG, "Error while creating a new configuration", e);
}
@@ -708,11 +708,11 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
final UartConfiguration configuration = serializer.read(UartConfiguration.class, xml);
final String name = configuration.getName();
if (!mDatabaseHelper.configurationExists(name)) {
final long id = mDatabaseHelper.addConfiguration(name, xml);
mWearableSynchronizer.onConfigurationAddedOrEdited(id, configuration);
if (!databaseHelper.configurationExists(name)) {
final long id = databaseHelper.addConfiguration(name, xml);
wearableSynchronizer.onConfigurationAddedOrEdited(id, configuration);
refreshConfigurations();
new Handler().post(() -> selectConfiguration(mConfigurationsAdapter.getItemPosition(id)));
new Handler().post(() -> selectConfiguration(configurationsAdapter.getItemPosition(id)));
} else {
Toast.makeText(this, R.string.uart_configuration_name_already_taken, Toast.LENGTH_LONG).show();
}
@@ -727,7 +727,7 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
else
message = "Unknown error";
final String msg = message;
Snackbar.make(mContainer, R.string.uart_configuration_loading_failed, Snackbar.LENGTH_INDEFINITE).setAction(R.string.uart_action_details, v -> new AlertDialog.Builder(UARTActivity.this).setMessage(msg).setTitle(R.string.uart_action_details).setPositiveButton(R.string.ok, null).show()).show();
Snackbar.make(container, R.string.uart_configuration_loading_failed, Snackbar.LENGTH_INDEFINITE).setAction(R.string.uart_action_details, v -> new AlertDialog.Builder(UARTActivity.this).setMessage(msg).setTitle(R.string.uart_action_details).setPositiveButton(R.string.ok, null).show()).show();
}
}
@@ -740,13 +740,13 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
if (!serverFolder.exists())
serverFolder.mkdir();
final String fileName = mConfiguration.getName() + ".xml";
final String fileName = configuration.getName() + ".xml";
final File file = new File(serverFolder, fileName);
try {
file.createNewFile();
final FileOutputStream fos = new FileOutputStream(file);
final OutputStreamWriter writer = new OutputStreamWriter(fos);
writer.append(mDatabaseHelper.getConfiguration(mConfigurationSpinner.getSelectedItemId()));
writer.append(databaseHelper.getConfiguration(configurationSpinner.getSelectedItemId()));
writer.close();
// Notify user about the file
@@ -768,21 +768,21 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
* Converts the old configuration, stored in preferences, into the first XML configuration and saves it to the database.
* If there is already any configuration in the database this method does nothing.
*/
private void ensureFirstConfiguration(final DatabaseHelper mDatabaseHelper) {
private void ensureFirstConfiguration(final DatabaseHelper databaseHelper) {
// This method ensures that the "old", single configuration has been saved to the database.
if (mDatabaseHelper.getConfigurationsCount() == 0) {
if (databaseHelper.getConfigurationsCount() == 0) {
final UartConfiguration configuration = new UartConfiguration();
configuration.setName("First configuration");
final Command[] commands = configuration.getCommands();
for (int i = 0; i < 9; ++i) {
final String cmd = mPreferences.getString(PREFS_BUTTON_COMMAND + i, null);
final String cmd = preferences.getString(PREFS_BUTTON_COMMAND + i, null);
if (cmd != null) {
final Command command = new Command();
command.setCommand(cmd);
command.setActive(mPreferences.getBoolean(PREFS_BUTTON_ENABLED + i, false));
command.setActive(preferences.getBoolean(PREFS_BUTTON_ENABLED + i, false));
command.setEol(0); // default one
command.setIconIndex(mPreferences.getInt(PREFS_BUTTON_ICON + i, 0));
command.setIconIndex(preferences.getInt(PREFS_BUTTON_ICON + i, 0));
commands[i] = command;
}
}
@@ -795,7 +795,7 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
serializer.write(configuration, writer);
final String xml = writer.toString();
mDatabaseHelper.addConfiguration(configuration.getName(), xml);
databaseHelper.addConfiguration(configuration.getName(), xml);
} catch (final Exception e) {
Log.e(TAG, "Error while creating default configuration", e);
}

View File

@@ -28,36 +28,38 @@ import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import no.nordicsemi.android.nrftoolbox.R;
import no.nordicsemi.android.nrftoolbox.uart.domain.Command;
import no.nordicsemi.android.nrftoolbox.uart.domain.UartConfiguration;
public class UARTButtonAdapter extends BaseAdapter {
private UartConfiguration mConfiguration;
private boolean mEditMode;
private UartConfiguration configuration;
private boolean editMode;
public UARTButtonAdapter(final UartConfiguration configuration) {
mConfiguration = configuration;
this.configuration = configuration;
}
public void setEditMode(final boolean editMode) {
mEditMode = editMode;
this.editMode = editMode;
notifyDataSetChanged();
}
public void setConfiguration(final UartConfiguration configuration) {
mConfiguration = configuration;
this.configuration = configuration;
notifyDataSetChanged();
}
@Override
public int getCount() {
return mConfiguration != null ? mConfiguration.getCommands().length : 0;
return configuration != null ? configuration.getCommands().length : 0;
}
@Override
public Object getItem(final int position) {
return mConfiguration.getCommands()[position];
return configuration.getCommands()[position];
}
@Override
@@ -76,20 +78,20 @@ public class UARTButtonAdapter extends BaseAdapter {
}
@Override
public boolean isEnabled(int position) {
public boolean isEnabled(final int position) {
final Command command = (Command) getItem(position);
return mEditMode || (command != null && command.isActive());
return editMode || (command != null && command.isActive());
}
@Override
public View getView(final int position, final View convertView, final ViewGroup parent) {
public View getView(final int position, @Nullable final View convertView, @NonNull final ViewGroup parent) {
View view = convertView;
if (view == null) {
final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
view = inflater.inflate(R.layout.feature_uart_button, parent, false);
}
view.setEnabled(isEnabled(position));
view.setActivated(mEditMode);
view.setActivated(editMode);
// Update image
final Command command = (Command) getItem(position);

View File

@@ -30,21 +30,23 @@ import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import no.nordicsemi.android.nrftoolbox.R;
public class UARTConfigurationsAdapter extends CursorAdapter {
final Context mContext;
final ActionListener mListener;
final Context context;
final ActionListener listener;
public interface ActionListener {
void onNewConfigurationClick();
void onImportClick();
}
public UARTConfigurationsAdapter(final Context context, final ActionListener listener, final Cursor c) {
public UARTConfigurationsAdapter(@NonNull final Context context, final ActionListener listener, final Cursor c) {
super(context, c, 0);
mContext = context;
mListener = listener;
this.context = context;
this.listener = listener;
}
@Override
@@ -83,7 +85,7 @@ public class UARTConfigurationsAdapter extends CursorAdapter {
}
@Override
public View getView(final int position, final View convertView, final ViewGroup parent) {
public View getView(final int position, @Nullable final View convertView, @NonNull final ViewGroup parent) {
if (position == 0) {
// This empty view should never be visible. Only positions 1+ are valid. Position 0 is reserved for action buttons.
// It is only created temporally when activity is created.
@@ -93,9 +95,9 @@ public class UARTConfigurationsAdapter extends CursorAdapter {
}
@Override
public View getDropDownView(final int position, final View convertView, final ViewGroup parent) {
public View getDropDownView(final int position, @Nullable final View convertView, @NonNull final ViewGroup parent) {
if (position == 0) {
return newToolbarView(mContext, parent);
return newToolbarView(context, parent);
}
if (convertView instanceof ViewGroup)
return super.getDropDownView(position - 1, null, parent);
@@ -104,18 +106,18 @@ public class UARTConfigurationsAdapter extends CursorAdapter {
@Override
public View newView(final Context context, final Cursor cursor, final ViewGroup parent) {
return LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_spinner_item, parent, false);
return LayoutInflater.from(context).inflate(android.R.layout.simple_spinner_item, parent, false);
}
@Override
public View newDropDownView(final Context context, final Cursor cursor, final ViewGroup parent) {
return LayoutInflater.from(mContext).inflate(R.layout.feature_uart_dropdown_item, parent, false);
return LayoutInflater.from(context).inflate(R.layout.feature_uart_dropdown_item, parent, false);
}
public View newToolbarView(final Context context, final ViewGroup parent) {
final View view = LayoutInflater.from(context).inflate(R.layout.feature_uart_dropdown_title, parent, false);
view.findViewById(R.id.action_add).setOnClickListener(v -> mListener.onNewConfigurationClick());
view.findViewById(R.id.action_import).setOnClickListener(v -> mListener.onImportClick());
view.findViewById(R.id.action_add).setOnClickListener(v -> listener.onNewConfigurationClick());
view.findViewById(R.id.action_import).setOnClickListener(v -> listener.onImportClick());
return view;
}

View File

@@ -24,6 +24,8 @@ package no.nordicsemi.android.nrftoolbox.uart;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
@@ -40,12 +42,12 @@ public class UARTControlFragment extends Fragment implements GridView.OnItemClic
private final static String TAG = "UARTControlFragment";
private final static String SIS_EDIT_MODE = "sis_edit_mode";
private UartConfiguration mConfiguration;
private UARTButtonAdapter mAdapter;
private boolean mEditMode;
private UartConfiguration configuration;
private UARTButtonAdapter adapter;
private boolean editMode;
@Override
public void onAttach(final Context context) {
public void onAttach(@NonNull final Context context) {
super.onAttach(context);
try {
@@ -60,19 +62,19 @@ public class UARTControlFragment extends Fragment implements GridView.OnItemClic
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
mEditMode = savedInstanceState.getBoolean(SIS_EDIT_MODE);
editMode = savedInstanceState.getBoolean(SIS_EDIT_MODE);
}
}
@Override
public void onDestroy() {
super.onDestroy();
((UARTActivity)getActivity()).setConfigurationListener(null);
((UARTActivity)requireActivity()).setConfigurationListener(null);
}
@Override
public void onSaveInstanceState(final Bundle outState) {
outState.putBoolean(SIS_EDIT_MODE, mEditMode);
outState.putBoolean(SIS_EDIT_MODE, editMode);
}
@Override
@@ -80,23 +82,23 @@ public class UARTControlFragment extends Fragment implements GridView.OnItemClic
final View view = inflater.inflate(R.layout.fragment_feature_uart_control, container, false);
final GridView grid = view.findViewById(R.id.grid);
grid.setAdapter(mAdapter = new UARTButtonAdapter(mConfiguration));
grid.setAdapter(adapter = new UARTButtonAdapter(configuration));
grid.setOnItemClickListener(this);
mAdapter.setEditMode(mEditMode);
adapter.setEditMode(editMode);
return view;
}
@Override
public void onItemClick(final AdapterView<?> parent, final View view, final int position, final long id) {
if (mEditMode) {
Command command = mConfiguration.getCommands()[position];
if (editMode) {
Command command = configuration.getCommands()[position];
if (command == null)
mConfiguration.getCommands()[position] = command = new Command();
configuration.getCommands()[position] = command = new Command();
final UARTEditDialog dialog = UARTEditDialog.getInstance(position, command);
dialog.show(getChildFragmentManager(), null);
} else {
final Command command = (Command)mAdapter.getItem(position);
final Command command = (Command)adapter.getItem(position);
final Command.Eol eol = command.getEol();
String text = command.getCommand();
if (text == null)
@@ -109,25 +111,25 @@ public class UARTControlFragment extends Fragment implements GridView.OnItemClic
text = text.replaceAll("\n", "\r");
break;
}
final UARTInterface uart = (UARTInterface) getActivity();
final UARTInterface uart = (UARTInterface) requireActivity();
uart.send(text);
}
}
@Override
public void onConfigurationModified() {
mAdapter.notifyDataSetChanged();
adapter.notifyDataSetChanged();
}
@Override
public void onConfigurationChanged(final UartConfiguration configuration) {
mConfiguration = configuration;
mAdapter.setConfiguration(configuration);
public void onConfigurationChanged(@NonNull final UartConfiguration configuration) {
this.configuration = configuration;
adapter.setConfiguration(configuration);
}
@Override
public void setEditMode(final boolean editMode) {
mEditMode = editMode;
mAdapter.setEditMode(mEditMode);
this.editMode = editMode;
adapter.setEditMode(editMode);
}
}

View File

@@ -25,6 +25,7 @@ package no.nordicsemi.android.nrftoolbox.uart;
import android.app.Dialog;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.DialogFragment;
import androidx.appcompat.app.AlertDialog;
import android.view.LayoutInflater;
@@ -47,12 +48,12 @@ public class UARTEditDialog extends DialogFragment implements View.OnClickListen
private final static String ARG_COMMAND = "command";
private final static String ARG_EOL = "eol";
private final static String ARG_ICON_INDEX = "iconIndex";
private int mActiveIcon;
private int activeIcon;
private EditText mField;
private CheckBox mActiveCheckBox;
private RadioGroup mEOLGroup;
private IconAdapter mIconAdapter;
private EditText field;
private CheckBox activeCheckBox;
private RadioGroup eolGroup;
private IconAdapter iconAdapter;
public static UARTEditDialog getInstance(final int index, final Command command) {
final UARTEditDialog fragment = new UARTEditDialog();
@@ -73,27 +74,27 @@ public class UARTEditDialog extends DialogFragment implements View.OnClickListen
final LayoutInflater inflater = LayoutInflater.from(getActivity());
// Read button configuration
final Bundle args = getArguments();
final Bundle args = requireArguments();
final int index = args.getInt(ARG_INDEX);
final String command = args.getString(ARG_COMMAND);
final int eol = args.getInt(ARG_EOL);
final int iconIndex = args.getInt(ARG_ICON_INDEX);
final boolean active = true; // change to active by default
mActiveIcon = iconIndex;
activeIcon = iconIndex;
// Create view
final View view = inflater.inflate(R.layout.feature_uart_dialog_edit, null);
final EditText field = mField = view.findViewById(R.id.field);
final EditText field = this.field = view.findViewById(R.id.field);
final GridView grid = view.findViewById(R.id.grid);
final CheckBox checkBox = mActiveCheckBox = view.findViewById(R.id.active);
final CheckBox checkBox = activeCheckBox = view.findViewById(R.id.active);
checkBox.setOnCheckedChangeListener((buttonView, isChecked) -> {
field.setEnabled(isChecked);
grid.setEnabled(isChecked);
if (mIconAdapter != null)
mIconAdapter.notifyDataSetChanged();
if (iconAdapter != null)
iconAdapter.notifyDataSetChanged();
});
final RadioGroup eolGroup = mEOLGroup = view.findViewById(R.id.uart_eol);
final RadioGroup eolGroup = this.eolGroup = view.findViewById(R.id.uart_eol);
switch (Command.Eol.values()[eol]) {
case CR_LF:
eolGroup.check(R.id.uart_eol_cr_lf);
@@ -112,11 +113,16 @@ public class UARTEditDialog extends DialogFragment implements View.OnClickListen
checkBox.setChecked(active);
grid.setOnItemClickListener(this);
grid.setEnabled(active);
grid.setAdapter(mIconAdapter = new IconAdapter());
grid.setAdapter(iconAdapter = new IconAdapter());
// As we want to have some validation we can't user the DialogInterface.OnClickListener as it's always dismissing the dialog.
final AlertDialog dialog = new AlertDialog.Builder(getActivity()).setCancelable(false).setTitle(R.string.uart_edit_title).setPositiveButton(R.string.ok, null)
.setNegativeButton(R.string.cancel, null).setView(view).show();
final AlertDialog dialog = new AlertDialog.Builder(requireContext())
.setCancelable(false)
.setTitle(R.string.uart_edit_title)
.setPositiveButton(R.string.ok, null)
.setNegativeButton(R.string.cancel, null)
.setView(view)
.show();
final Button okButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
okButton.setOnClickListener(this);
return dialog;
@@ -124,11 +130,11 @@ public class UARTEditDialog extends DialogFragment implements View.OnClickListen
@Override
public void onClick(final View v) {
final boolean active = mActiveCheckBox.isChecked();
final String command = mField.getText().toString();
final boolean active = activeCheckBox.isChecked();
final String command = field.getText().toString();
int eol;
switch (mEOLGroup.getCheckedRadioButtonId()) {
switch (eolGroup.getCheckedRadioButtonId()) {
case R.id.uart_eol_cr_lf:
eol = Command.Eol.CR_LF.index;
break;
@@ -142,18 +148,18 @@ public class UARTEditDialog extends DialogFragment implements View.OnClickListen
}
// Save values
final Bundle args = getArguments();
final Bundle args = requireArguments();
final int index = args.getInt(ARG_INDEX);
dismiss();
final UARTActivity parent = (UARTActivity) getActivity();
parent.onCommandChanged(index, command, active, eol, mActiveIcon);
final UARTActivity parent = (UARTActivity) requireActivity();
parent.onCommandChanged(index, command, active, eol, activeIcon);
}
@Override
public void onItemClick(final AdapterView<?> parent, final View view, final int position, final long id) {
mActiveIcon = position;
mIconAdapter.notifyDataSetChanged();
activeIcon = position;
iconAdapter.notifyDataSetChanged();
}
private class IconAdapter extends BaseAdapter {
@@ -175,14 +181,15 @@ public class UARTEditDialog extends DialogFragment implements View.OnClickListen
}
@Override
public View getView(final int position, final View convertView, final ViewGroup parent) {
public View getView(final int position, @Nullable final View convertView, @NonNull final ViewGroup parent) {
View view = convertView;
if (view == null) {
view = LayoutInflater.from(getActivity()).inflate(R.layout.feature_uart_dialog_edit_icon, parent, false);
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.feature_uart_dialog_edit_icon, parent, false);
}
final ImageView image = (ImageView) view;
image.setImageLevel(position);
image.setActivated(position == mActiveIcon && mActiveCheckBox.isChecked());
image.setActivated(position == activeIcon && activeCheckBox.isChecked());
return view;
}
}

View File

@@ -39,15 +39,15 @@ import no.nordicsemi.android.log.LogContract.Log.Level;
import no.nordicsemi.android.nrftoolbox.R;
public class UARTLogAdapter extends CursorAdapter {
private static final SparseIntArray mColors = new SparseIntArray();
private static final SparseIntArray colors = new SparseIntArray();
static {
mColors.put(Level.DEBUG, 0xFF009CDE);
mColors.put(Level.VERBOSE, 0xFFB8B056);
mColors.put(Level.INFO, Color.BLACK);
mColors.put(Level.APPLICATION, 0xFF238C0F);
mColors.put(Level.WARNING, 0xFFD77926);
mColors.put(Level.ERROR, Color.RED);
colors.put(Level.DEBUG, 0xFF009CDE);
colors.put(Level.VERBOSE, 0xFFB8B056);
colors.put(Level.INFO, Color.BLACK);
colors.put(Level.APPLICATION, 0xFF238C0F);
colors.put(Level.WARNING, 0xFFD77926);
colors.put(Level.ERROR, Color.RED);
}
UARTLogAdapter(@NonNull final Context context) {
@@ -74,7 +74,7 @@ public class UARTLogAdapter extends CursorAdapter {
final int level = cursor.getInt(2 /* LEVEL */);
holder.data.setText(cursor.getString(3 /* DATA */));
holder.data.setTextColor(mColors.get(level));
holder.data.setTextColor(colors.get(level));
}
@Override

View File

@@ -63,28 +63,28 @@ public class UARTLogFragment extends ListFragment implements LoaderManager.Loade
/**
* The service UART interface that may be used to send data to the target.
*/
private UARTInterface mUARTInterface;
private UARTInterface uartInterface;
/**
* The adapter used to populate the list with log entries.
*/
private CursorAdapter mLogAdapter;
private CursorAdapter logAdapter;
/**
* The log session created to log events related with the target device.
*/
private ILogSession mLogSession;
private ILogSession logSession;
private EditText mField;
private Button mSendButton;
private EditText field;
private Button sendButton;
/**
* The last list view position.
*/
private int mLogScrollPosition;
private int logScrollPosition;
/**
* The receiver that listens for {@link BleProfileService#BROADCAST_CONNECTION_STATE} action.
*/
private final BroadcastReceiver mCommonBroadcastReceiver = new BroadcastReceiver() {
private final BroadcastReceiver commonBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
// This receiver listens only for the BleProfileService.BROADCAST_CONNECTION_STATE action, no need to check it.
@@ -109,15 +109,15 @@ public class UARTLogFragment extends ListFragment implements LoaderManager.Loade
}
};
private ServiceConnection mServiceConnection = new ServiceConnection() {
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(final ComponentName name, final IBinder service) {
final UARTService.UARTBinder bleService = (UARTService.UARTBinder) service;
mUARTInterface = bleService;
mLogSession = bleService.getLogSession();
uartInterface = bleService;
logSession = bleService.getLogSession();
// Start the loader
if (mLogSession != null) {
if (logSession != null) {
getLoaderManager().restartLoader(LOG_REQUEST_ID, null, UARTLogFragment.this);
}
@@ -129,7 +129,7 @@ public class UARTLogFragment extends ListFragment implements LoaderManager.Loade
@Override
public void onServiceDisconnected(final ComponentName name) {
onDeviceDisconnected();
mUARTInterface = null;
uartInterface = null;
}
};
@@ -137,11 +137,11 @@ public class UARTLogFragment extends ListFragment implements LoaderManager.Loade
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LocalBroadcastManager.getInstance(requireContext()).registerReceiver(mCommonBroadcastReceiver, makeIntentFilter());
LocalBroadcastManager.getInstance(requireContext()).registerReceiver(commonBroadcastReceiver, makeIntentFilter());
// Load the last log list view scroll position
if (savedInstanceState != null) {
mLogScrollPosition = savedInstanceState.getInt(SIS_LOG_SCROLL_POSITION);
logScrollPosition = savedInstanceState.getInt(SIS_LOG_SCROLL_POSITION);
}
}
@@ -151,10 +151,10 @@ public class UARTLogFragment extends ListFragment implements LoaderManager.Loade
/*
* If the service has not been started before the following lines will not start it. However, if it's running, the Activity will be bound to it
* and notified via mServiceConnection.
* and notified via serviceConnection.
*/
final Intent service = new Intent(getActivity(), UARTService.class);
requireActivity().bindService(service, mServiceConnection, 0); // we pass 0 as a flag so the service will not be created if not exists
requireActivity().bindService(service, serviceConnection, 0); // we pass 0 as a flag so the service will not be created if not exists
}
@Override
@@ -162,8 +162,8 @@ public class UARTLogFragment extends ListFragment implements LoaderManager.Loade
super.onStop();
try {
requireActivity().unbindService(mServiceConnection);
mUARTInterface = null;
requireActivity().unbindService(serviceConnection);
uartInterface = null;
} catch (final IllegalArgumentException e) {
// do nothing, we were not connected to the sensor
}
@@ -181,7 +181,7 @@ public class UARTLogFragment extends ListFragment implements LoaderManager.Loade
@Override
public void onDestroy() {
LocalBroadcastManager.getInstance(requireContext()).unregisterReceiver(mCommonBroadcastReceiver);
LocalBroadcastManager.getInstance(requireContext()).unregisterReceiver(commonBroadcastReceiver);
super.onDestroy();
}
@@ -189,7 +189,7 @@ public class UARTLogFragment extends ListFragment implements LoaderManager.Loade
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_feature_uart_log, container, false);
final EditText field = mField = view.findViewById(R.id.field);
final EditText field = this.field = view.findViewById(R.id.field);
field.setOnEditorActionListener((v, actionId, event) -> {
if (actionId == EditorInfo.IME_ACTION_SEND) {
onSendClicked();
@@ -198,7 +198,7 @@ public class UARTLogFragment extends ListFragment implements LoaderManager.Loade
return false;
});
final Button sendButton = mSendButton = view.findViewById(R.id.action_send);
final Button sendButton = this.sendButton = view.findViewById(R.id.action_send);
sendButton.setOnClickListener(v -> onSendClicked());
return view;
}
@@ -208,8 +208,8 @@ public class UARTLogFragment extends ListFragment implements LoaderManager.Loade
super.onViewCreated(view, savedInstanceState);
// Create the log adapter, initially with null cursor
mLogAdapter = new UARTLogAdapter(requireContext());
setListAdapter(mLogAdapter);
logAdapter = new UARTLogAdapter(requireContext());
setListAdapter(logAdapter);
}
@NonNull
@@ -217,7 +217,7 @@ public class UARTLogFragment extends ListFragment implements LoaderManager.Loade
public Loader<Cursor> onCreateLoader(final int id, final Bundle args) {
switch (id) {
case LOG_REQUEST_ID: {
return new CursorLoader(requireContext(), mLogSession.getSessionEntriesUri(), LOG_PROJECTION, null, null, LogContract.Log.TIME);
return new CursorLoader(requireContext(), logSession.getSessionEntriesUri(), LOG_PROJECTION, null, null, LogContract.Log.TIME);
}
}
throw new UnsupportedOperationException("Could not create loader with ID " + id);
@@ -227,10 +227,10 @@ public class UARTLogFragment extends ListFragment implements LoaderManager.Loade
public void onLoadFinished(@NonNull final Loader<Cursor> loader, final Cursor data) {
// Here we have to restore the old saved scroll position, or scroll to the bottom if before adding new events it was scrolled to the bottom.
final ListView list = getListView();
final int position = mLogScrollPosition;
final int position = logScrollPosition;
final boolean scrolledToBottom = position == LOG_SCROLLED_TO_BOTTOM || (list.getCount() > 0 && list.getLastVisiblePosition() == list.getCount() - 1);
mLogAdapter.swapCursor(data);
logAdapter.swapCursor(data);
if (position > LOG_SCROLL_NULL) {
list.setSelectionFromTop(position, 0);
@@ -238,21 +238,21 @@ public class UARTLogFragment extends ListFragment implements LoaderManager.Loade
if (scrolledToBottom)
list.setSelection(list.getCount() - 1);
}
mLogScrollPosition = LOG_SCROLL_NULL;
logScrollPosition = LOG_SCROLL_NULL;
}
@Override
public void onLoaderReset(@NonNull final Loader<Cursor> loader) {
mLogAdapter.swapCursor(null);
logAdapter.swapCursor(null);
}
private void onSendClicked() {
final String text = mField.getText().toString();
final String text = field.getText().toString();
mUARTInterface.send(text);
uartInterface.send(text);
mField.setText(null);
mField.requestFocus();
field.setText(null);
field.requestFocus();
}
/**
@@ -262,7 +262,7 @@ public class UARTLogFragment extends ListFragment implements LoaderManager.Loade
public void onServiceStarted() {
// The service has been started, bind to it
final Intent service = new Intent(getActivity(), UARTService.class);
requireActivity().bindService(service, mServiceConnection, 0);
requireActivity().bindService(service, serviceConnection, 0);
}
/**
@@ -271,7 +271,7 @@ public class UARTLogFragment extends ListFragment implements LoaderManager.Loade
public void onFragmentHidden() {
final InputMethodManager imm = (InputMethodManager) requireContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
imm.hideSoftInputFromWindow(mField.getWindowToken(), 0);
imm.hideSoftInputFromWindow(field.getWindowToken(), 0);
}
}
@@ -279,16 +279,16 @@ public class UARTLogFragment extends ListFragment implements LoaderManager.Loade
* Method called when the target device has connected.
*/
protected void onDeviceConnected() {
mField.setEnabled(true);
mSendButton.setEnabled(true);
field.setEnabled(true);
sendButton.setEnabled(true);
}
/**
* Method called when user disconnected from the target UART device or the connection was lost.
*/
protected void onDeviceDisconnected() {
mField.setEnabled(false);
mSendButton.setEnabled(false);
field.setEnabled(false);
sendButton.setEnabled(false);
}
private static IntentFilter makeIntentFilter() {

View File

@@ -43,7 +43,7 @@ public class UARTManager extends LoggableBleManager<UARTManagerCallbacks> {
/** TX characteristic UUID */
private final static UUID UART_TX_CHARACTERISTIC_UUID = UUID.fromString("6E400003-B5A3-F393-E0A9-E50E24DCCA9E");
private BluetoothGattCharacteristic mRXCharacteristic, mTXCharacteristic;
private BluetoothGattCharacteristic rxCharacteristic, txCharacteristic;
/**
* A flag indicating whether Long Write can be used. It's set to false if the UART RX
* characteristic has only PROPERTY_WRITE_NO_RESPONSE property and no PROPERTY_WRITE.
@@ -51,7 +51,7 @@ public class UARTManager extends LoggableBleManager<UARTManagerCallbacks> {
*
* TODO change this flag if you don't want to use Long Write even with Write Request.
*/
private boolean mUseLongWrite = true;
private boolean useLongWrite = true;
UARTManager(final Context context) {
super(context);
@@ -60,39 +60,39 @@ public class UARTManager extends LoggableBleManager<UARTManagerCallbacks> {
@NonNull
@Override
protected BleManagerGattCallback getGattCallback() {
return mGattCallback;
return gattCallback;
}
/**
* BluetoothGatt callbacks for connection/disconnection, service discovery,
* receiving indication, etc.
*/
private final BleManagerGattCallback mGattCallback = new BleManagerGattCallback() {
private final BleManagerGattCallback gattCallback = new BleManagerGattCallback() {
@Override
protected void initialize() {
setNotificationCallback(mTXCharacteristic)
setNotificationCallback(txCharacteristic)
.with((device, data) -> {
final String text = data.getStringValue(0);
log(LogContract.Log.Level.APPLICATION, "\"" + text + "\" received");
mCallbacks.onDataReceived(device, text);
callbacks.onDataReceived(device, text);
});
requestMtu(260).enqueue();
enableNotifications(mTXCharacteristic).enqueue();
enableNotifications(txCharacteristic).enqueue();
}
@Override
public boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) {
final BluetoothGattService service = gatt.getService(UART_SERVICE_UUID);
if (service != null) {
mRXCharacteristic = service.getCharacteristic(UART_RX_CHARACTERISTIC_UUID);
mTXCharacteristic = service.getCharacteristic(UART_TX_CHARACTERISTIC_UUID);
rxCharacteristic = service.getCharacteristic(UART_RX_CHARACTERISTIC_UUID);
txCharacteristic = service.getCharacteristic(UART_TX_CHARACTERISTIC_UUID);
}
boolean writeRequest = false;
boolean writeCommand = false;
if (mRXCharacteristic != null) {
final int rxProperties = mRXCharacteristic.getProperties();
if (rxCharacteristic != null) {
final int rxProperties = rxCharacteristic.getProperties();
writeRequest = (rxProperties & BluetoothGattCharacteristic.PROPERTY_WRITE) > 0;
writeCommand = (rxProperties & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) > 0;
@@ -101,19 +101,19 @@ public class UARTManager extends LoggableBleManager<UARTManagerCallbacks> {
// In case there is no WRITE REQUEST property, this manager will divide texts
// longer then MTU-3 bytes into up to MTU-3 bytes chunks.
if (writeRequest)
mRXCharacteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
rxCharacteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
else
mUseLongWrite = false;
useLongWrite = false;
}
return mRXCharacteristic != null && mTXCharacteristic != null && (writeRequest || writeCommand);
return rxCharacteristic != null && txCharacteristic != null && (writeRequest || writeCommand);
}
@Override
protected void onDeviceDisconnected() {
mRXCharacteristic = null;
mTXCharacteristic = null;
mUseLongWrite = true;
rxCharacteristic = null;
txCharacteristic = null;
useLongWrite = true;
}
};
@@ -130,14 +130,14 @@ public class UARTManager extends LoggableBleManager<UARTManagerCallbacks> {
*/
public void send(final String text) {
// Are we connected?
if (mRXCharacteristic == null)
if (rxCharacteristic == null)
return;
if (!TextUtils.isEmpty(text)) {
final WriteRequest request = writeCharacteristic(mRXCharacteristic, text.getBytes())
final WriteRequest request = writeCharacteristic(rxCharacteristic, text.getBytes())
.with((device, data) -> log(LogContract.Log.Level.APPLICATION,
"\"" + data.getStringValue(0) + "\" sent"));
if (!mUseLongWrite) {
if (!useLongWrite) {
// This will automatically split the long data into MTU-3-byte long packets.
request.split();
}

View File

@@ -24,11 +24,12 @@ package no.nordicsemi.android.nrftoolbox.uart;
import android.bluetooth.BluetoothDevice;
import androidx.annotation.NonNull;
import no.nordicsemi.android.ble.BleManagerCallbacks;
public interface UARTManagerCallbacks extends BleManagerCallbacks {
void onDataReceived(final BluetoothDevice device, final String data);
void onDataReceived(@NonNull final BluetoothDevice device, final String data);
void onDataSent(final BluetoothDevice device, final String data);
void onDataSent(@NonNull final BluetoothDevice device, final String data);
}

View File

@@ -40,9 +40,9 @@ public class UARTNewConfigurationDialogFragment extends DialogFragment implement
private static final String NAME = "name";
private static final String DUPLICATE = "duplicate";
private EditText mEditText;
private EditText editText;
private NewConfigurationDialogListener mListener;
private NewConfigurationDialogListener listener;
public interface NewConfigurationDialogListener {
/**
@@ -60,11 +60,11 @@ public class UARTNewConfigurationDialogFragment extends DialogFragment implement
}
@Override
public void onAttach(final Context context) {
public void onAttach(@NonNull final Context context) {
super.onAttach(context);
if (context instanceof NewConfigurationDialogListener) {
mListener = (NewConfigurationDialogListener) context;
listener = (NewConfigurationDialogListener) context;
} else {
throw new IllegalArgumentException("The parent activity must implement NewConfigurationDialogListener");
}
@@ -73,7 +73,7 @@ public class UARTNewConfigurationDialogFragment extends DialogFragment implement
@Override
public void onDetach() {
super.onDetach();
mListener = null;
listener = null;
}
public static DialogFragment getInstance(final String name, final boolean duplicate) {
@@ -90,22 +90,25 @@ public class UARTNewConfigurationDialogFragment extends DialogFragment implement
@Override
@NonNull
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final Context context = getActivity();
final Bundle args = getArguments();
final Bundle args = requireArguments();
final String oldName = args.getString(NAME);
final boolean duplicate = args.getBoolean(DUPLICATE);
final int titleResId = duplicate || oldName == null ? R.string.uart_new_configuration_title : R.string.uart_rename_configuration_title;
final LayoutInflater inflater = LayoutInflater.from(getActivity());
final LayoutInflater inflater = LayoutInflater.from(requireContext());
final View view = inflater.inflate(R.layout.feature_uart_dialog_new_configuration, null);
final EditText editText = mEditText = view.findViewById(R.id.name);
final EditText editText = this.editText = view.findViewById(R.id.name);
editText.setText(args.getString(NAME));
final View actionClear = view.findViewById(R.id.action_clear);
actionClear.setOnClickListener(v -> editText.setText(null));
final AlertDialog dialog = new AlertDialog.Builder(context).setTitle(titleResId).setView(view).setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.ok, null).setCancelable(false).show(); // this must be show() or the getButton() below will return null.
final AlertDialog dialog = new AlertDialog.Builder(requireContext())
.setTitle(titleResId)
.setView(view)
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.ok, null)
.setCancelable(false)
.show(); // this must be show() or the getButton() below will return null.
final Button okButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
okButton.setOnClickListener(this);
@@ -115,19 +118,20 @@ public class UARTNewConfigurationDialogFragment extends DialogFragment implement
@Override
public void onClick(final View v) {
final String newName = mEditText.getText().toString().trim();
final String newName = editText.getText().toString().trim();
if (TextUtils.isEmpty(newName)) {
mEditText.setError(getString(R.string.uart_empty_name_error));
editText.setError(getString(R.string.uart_empty_name_error));
return;
}
final String oldName = getArguments().getString(NAME);
final boolean duplicate = getArguments().getBoolean(DUPLICATE);
final Bundle args = requireArguments();
final String oldName = args.getString(NAME);
final boolean duplicate = args.getBoolean(DUPLICATE);
if (duplicate || TextUtils.isEmpty(oldName))
mListener.onNewConfiguration(newName, duplicate);
listener.onNewConfiguration(newName, duplicate);
else {
mListener.onRenameConfiguration(newName);
listener.onRenameConfiguration(newName);
}
dismiss();
}

View File

@@ -82,26 +82,26 @@ public class UARTService extends BleProfileService implements UARTManagerCallbac
private final static int OPEN_ACTIVITY_REQ = 67; // random
private final static int DISCONNECT_REQ = 97; // random
private GoogleApiClient mGoogleApiClient;
private UARTManager mManager;
private GoogleApiClient googleApiClient;
private UARTManager manager;
private final LocalBinder mBinder = new UARTBinder();
private final LocalBinder binder = new UARTBinder();
public class UARTBinder extends LocalBinder implements UARTInterface {
@Override
public void send(final String text) {
mManager.send(text);
manager.send(text);
}
}
@Override
protected LocalBinder getBinder() {
return mBinder;
return binder;
}
@Override
protected LoggableBleManager<UARTManagerCallbacks> initializeManager() {
return mManager = new UARTManager(this);
return manager = new UARTManager(this);
}
@Override
@@ -113,23 +113,23 @@ public class UARTService extends BleProfileService implements UARTManagerCallbac
public void onCreate() {
super.onCreate();
registerReceiver(mDisconnectActionBroadcastReceiver, new IntentFilter(ACTION_DISCONNECT));
registerReceiver(mIntentBroadcastReceiver, new IntentFilter(ACTION_SEND));
registerReceiver(disconnectActionBroadcastReceiver, new IntentFilter(ACTION_DISCONNECT));
registerReceiver(intentBroadcastReceiver, new IntentFilter(ACTION_SEND));
mGoogleApiClient = new GoogleApiClient.Builder(this)
googleApiClient = new GoogleApiClient.Builder(this)
.addApi(Wearable.API)
.build();
mGoogleApiClient.connect();
googleApiClient.connect();
}
@Override
public void onDestroy() {
// when user has disconnected from the sensor, we have to cancel the notification that we've created some milliseconds before using unbindService
stopForegroundService();
unregisterReceiver(mDisconnectActionBroadcastReceiver);
unregisterReceiver(mIntentBroadcastReceiver);
unregisterReceiver(disconnectActionBroadcastReceiver);
unregisterReceiver(intentBroadcastReceiver);
mGoogleApiClient.disconnect();
googleApiClient.disconnect();
super.onDestroy();
}
@@ -174,7 +174,7 @@ public class UARTService extends BleProfileService implements UARTManagerCallbac
}
@Override
public void onDataReceived(final BluetoothDevice device, final String data) {
public void onDataReceived(@NonNull final BluetoothDevice device, final String data) {
final Intent broadcast = new Intent(BROADCAST_UART_RX);
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
broadcast.putExtra(EXTRA_DATA, data);
@@ -188,7 +188,7 @@ public class UARTService extends BleProfileService implements UARTManagerCallbac
}
@Override
public void onDataSent(final BluetoothDevice device, final String data) {
public void onDataSent(@NonNull final BluetoothDevice device, final String data) {
final Intent broadcast = new Intent(BROADCAST_UART_TX);
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
broadcast.putExtra(EXTRA_DATA, data);
@@ -201,13 +201,13 @@ public class UARTService extends BleProfileService implements UARTManagerCallbac
* @param path message path
* @param message the message
*/
private void sendMessageToWearables(final @NonNull String path, final @NonNull String message) {
if (mGoogleApiClient.isConnected()) {
private void sendMessageToWearables(@NonNull final String path, @NonNull final String message) {
if (googleApiClient.isConnected()) {
new Thread(() -> {
NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).await();
NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
for (Node node : nodes.getNodes()) {
Logger.v(getLogSession(), "[WEAR] Sending message '" + path + "' to " + node.getDisplayName());
final MessageApi.SendMessageResult result = Wearable.MessageApi.sendMessage(mGoogleApiClient, node.getId(), path, message.getBytes()).await();
final MessageApi.SendMessageResult result = Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), path, message.getBytes()).await();
if (result.getStatus().isSuccess()) {
Logger.i(getLogSession(), "[WEAR] Message sent");
} else {
@@ -259,6 +259,7 @@ public class UARTService extends BleProfileService implements UARTManagerCallbac
* f.e. <code>&lt;string name="name"&gt;%s is connected&lt;/string&gt;</code>
* @param defaults signals that will be used to notify the user
*/
@SuppressWarnings("SameParameterValue")
protected Notification createNotification(final int messageResId, final int defaults) {
final Intent parentIntent = new Intent(this, FeaturesActivity.class);
parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -291,7 +292,7 @@ public class UARTService extends BleProfileService implements UARTManagerCallbac
/**
* This broadcast receiver listens for {@link #ACTION_DISCONNECT} that may be fired by pressing Disconnect action button on the notification.
*/
private final BroadcastReceiver mDisconnectActionBroadcastReceiver = new BroadcastReceiver() {
private final BroadcastReceiver disconnectActionBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
final int source = intent.getIntExtra(EXTRA_SOURCE, SOURCE_NOTIFICATION);
@@ -314,7 +315,7 @@ public class UARTService extends BleProfileService implements UARTManagerCallbac
* Broadcast receiver that listens for {@link #ACTION_SEND} from other apps. Sends the String or int content of the {@link Intent#EXTRA_TEXT} extra to the remote device.
* The integer content will be sent as String (65 -> "65", not 65 -> "A").
*/
private BroadcastReceiver mIntentBroadcastReceiver = new BroadcastReceiver() {
private BroadcastReceiver intentBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
final boolean hasMessage = intent.hasExtra(Intent.EXTRA_TEXT);
@@ -337,7 +338,7 @@ public class UARTService extends BleProfileService implements UARTManagerCallbac
Logger.i(getLogSession(), "[Broadcast] " + ACTION_SEND + " broadcast received with data: \"" + message + "\"");
break;
}
mManager.send(message);
manager.send(message);
return;
}
}

View File

@@ -28,6 +28,7 @@ import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.provider.BaseColumns;
@SuppressWarnings("UnusedReturnValue")
public class DatabaseHelper {
/** Database file name */
private static final String DATABASE_NAME = "toolbox_uart.db";
@@ -41,23 +42,27 @@ public class DatabaseHelper {
private static final String[] ID_PROJECTION = new String[] { BaseColumns._ID };
private static final String[] NAME_PROJECTION = new String[] { BaseColumns._ID, NameColumns.NAME };
private static final String[] XML_PROJECTION = new String[] { BaseColumns._ID, ConfigurationContract.Configuration.XML };
private static final String[] CONFIGURATION_PROJECTION = new String[] { BaseColumns._ID, NameColumns.NAME, ConfigurationContract.Configuration.XML };
private static final String[] XML_PROJECTION = new String[] {
BaseColumns._ID, ConfigurationContract.Configuration.XML
};
private static final String[] CONFIGURATION_PROJECTION = new String[] {
BaseColumns._ID, NameColumns.NAME, ConfigurationContract.Configuration.XML
};
private static final String ID_SELECTION = BaseColumns._ID + "=?";
private static final String NAME_SELECTION = NameColumns.NAME + "=?";
private static final String DELETED_SELECTION = UndoColumns.DELETED + "=1";
private static final String NOT_DELETED_SELECTION = UndoColumns.DELETED + "=0";
private static SQLiteHelper mDatabaseHelper;
private static SQLiteDatabase mDatabase;
private final ContentValues mValues = new ContentValues();
private final String[] mSingleArg = new String[1];
private static SQLiteHelper databaseHelper;
private static SQLiteDatabase database;
private final ContentValues values = new ContentValues();
private final String[] singleArg = new String[1];
public DatabaseHelper(final Context context) {
if (mDatabaseHelper == null) {
mDatabaseHelper = new SQLiteHelper(context);
mDatabase = mDatabaseHelper.getWritableDatabase();
if (databaseHelper == null) {
databaseHelper = new SQLiteHelper(context);
database = databaseHelper.getWritableDatabase();
}
}
@@ -65,11 +70,9 @@ public class DatabaseHelper {
* Returns number of saved configurations.
*/
public int getConfigurationsCount() {
final Cursor cursor = mDatabase.query(Tables.CONFIGURATIONS, ID_PROJECTION, NOT_DELETED_SELECTION, null, null, null, null);
try {
try (Cursor cursor = database.query(Tables.CONFIGURATIONS, ID_PROJECTION, NOT_DELETED_SELECTION,
null, null, null, null)) {
return cursor.getCount();
} finally {
cursor.close();
}
}
@@ -78,91 +81,95 @@ public class DatabaseHelper {
* @return cursor
*/
public Cursor getConfigurations() {
return mDatabase.query(Tables.CONFIGURATIONS, CONFIGURATION_PROJECTION, NOT_DELETED_SELECTION, null, null, null, ConfigurationContract.Configuration.NAME + " ASC");
return database.query(Tables.CONFIGURATIONS, CONFIGURATION_PROJECTION, NOT_DELETED_SELECTION,
null, null, null, ConfigurationContract.Configuration.NAME + " ASC");
}
/**
* Returns the list of names of all saved configurations.
*
* @return cursor
*/
public Cursor getConfigurationsNames() {
return mDatabase.query(Tables.CONFIGURATIONS, NAME_PROJECTION, NOT_DELETED_SELECTION, null, null, null, ConfigurationContract.Configuration.NAME + " ASC");
return database.query(Tables.CONFIGURATIONS, NAME_PROJECTION, NOT_DELETED_SELECTION,
null, null, null, ConfigurationContract.Configuration.NAME + " ASC");
}
/**
* Returns the XML wth the configuration by id.
*
* @param id the configuration id in the DB
* @return the XML with configuration or null
*/
public String getConfiguration(final long id) {
mSingleArg[0] = String.valueOf(id);
singleArg[0] = String.valueOf(id);
final Cursor cursor = mDatabase.query(Tables.CONFIGURATIONS, XML_PROJECTION, ID_SELECTION, mSingleArg, null, null, null);
try {
try (Cursor cursor = database.query(Tables.CONFIGURATIONS, XML_PROJECTION, ID_SELECTION,
singleArg, null, null, null)) {
if (cursor.moveToNext())
return cursor.getString(1 /* XML */);
return null;
} finally {
cursor.close();
}
}
/**
* Adds new configuration to the database.
*
* @param name the configuration name
* @param configuration the XML
* @return the id or -1 if error occurred
*/
public long addConfiguration(final String name, final String configuration) {
final ContentValues values = mValues;
final ContentValues values = this.values;
values.clear();
values.put(ConfigurationContract.Configuration.NAME, name);
values.put(ConfigurationContract.Configuration.XML, configuration);
values.put(ConfigurationContract.Configuration.DELETED, 0);
return mDatabase.replace(Tables.CONFIGURATIONS, null, values);
return database.replace(Tables.CONFIGURATIONS, null, values);
}
/**
* Updates the configuration with the given name with the new XML
* Updates the configuration with the given name with the new XML.
*
* @param name the configuration name to be updated
* @param configuration the new XML with configuration
* @return number of rows updated
*/
public int updateConfiguration(final String name, final String configuration) {
mSingleArg[0] = name;
singleArg[0] = name;
final ContentValues values = mValues;
final ContentValues values = this.values;
values.clear();
values.put(ConfigurationContract.Configuration.XML, configuration);
values.put(ConfigurationContract.Configuration.DELETED, 0);
return mDatabase.update(Tables.CONFIGURATIONS, values, NAME_SELECTION, mSingleArg);
return database.update(Tables.CONFIGURATIONS, values, NAME_SELECTION, singleArg);
}
/**
* Marks the configuration with given name as deleted. If may be restored or removed permanently afterwards.
* Marks the configuration with given name as deleted. If may be restored or removed permanently
* afterwards.
*
* @param name the configuration name
* @return id of the deleted configuration
*/
public long deleteConfiguration(final String name) {
mSingleArg[0] = name;
singleArg[0] = name;
final ContentValues values = mValues;
final ContentValues values = this.values;
values.clear();
values.put(ConfigurationContract.Configuration.DELETED, 1);
mDatabase.update(Tables.CONFIGURATIONS, values, NAME_SELECTION, mSingleArg);
database.update(Tables.CONFIGURATIONS, values, NAME_SELECTION, singleArg);
final Cursor cursor = mDatabase.query(Tables.CONFIGURATIONS, ID_PROJECTION, NAME_SELECTION, mSingleArg, null, null, null);
try {
try (Cursor cursor = database.query(Tables.CONFIGURATIONS, ID_PROJECTION, NAME_SELECTION,
singleArg, null, null, null)) {
if (cursor.moveToNext())
return cursor.getLong(0 /* _ID */);
return -1;
} finally {
cursor.close();
}
}
public int removeDeletedServerConfigurations() {
return mDatabase.delete(Tables.CONFIGURATIONS, DELETED_SELECTION, null);
return database.delete(Tables.CONFIGURATIONS, DELETED_SELECTION, null);
}
/**
@@ -170,20 +177,18 @@ public class DatabaseHelper {
* @return the DI of the restored configuration.
*/
public long restoreDeletedServerConfiguration(final String name) {
mSingleArg[0] = name;
singleArg[0] = name;
final ContentValues values = mValues;
final ContentValues values = this.values;
values.clear();
values.put(ConfigurationContract.Configuration.DELETED, 0);
mDatabase.update(Tables.CONFIGURATIONS, values, NAME_SELECTION, mSingleArg);
database.update(Tables.CONFIGURATIONS, values, NAME_SELECTION, singleArg);
final Cursor cursor = mDatabase.query(Tables.CONFIGURATIONS, ID_PROJECTION, NAME_SELECTION, mSingleArg, null, null, null);
try {
try (Cursor cursor = database.query(Tables.CONFIGURATIONS, ID_PROJECTION, NAME_SELECTION, singleArg,
null, null, null)) {
if (cursor.moveToNext())
return cursor.getLong(0 /* _ID */);
return -1;
} finally {
cursor.close();
}
}
@@ -195,13 +200,13 @@ public class DatabaseHelper {
* @return number of rows affected
*/
public int renameConfiguration(final String oldName, final String newName, final String configuration) {
mSingleArg[0] = oldName;
singleArg[0] = oldName;
final ContentValues values = mValues;
final ContentValues values = this.values;
values.clear();
values.put(ConfigurationContract.Configuration.NAME, newName);
values.put(ConfigurationContract.Configuration.XML, configuration);
return mDatabase.update(Tables.CONFIGURATIONS, values, NAME_SELECTION, mSingleArg);
return database.update(Tables.CONFIGURATIONS, values, NAME_SELECTION, singleArg);
}
/**
@@ -210,13 +215,11 @@ public class DatabaseHelper {
* @return true if such name exists, false otherwise
*/
public boolean configurationExists(final String name) {
mSingleArg[0] = name;
singleArg[0] = name;
final Cursor cursor = mDatabase.query(Tables.CONFIGURATIONS, NAME_PROJECTION, NAME_SELECTION + " AND " + NOT_DELETED_SELECTION, mSingleArg, null, null, null);
try {
try (Cursor cursor = database.query(Tables.CONFIGURATIONS, NAME_PROJECTION, NAME_SELECTION
+ " AND " + NOT_DELETED_SELECTION, singleArg, null, null, null)) {
return cursor.getCount() > 0;
} finally {
cursor.close();
}
}
@@ -233,12 +236,13 @@ public class DatabaseHelper {
* ----------------------------------------------------------------------------
* </pre>
*/
private static final String CREATE_CONFIGURATIONS = "CREATE TABLE " + Tables.CONFIGURATIONS+ "(" + ConfigurationContract.Configuration._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ ConfigurationContract.Configuration.NAME + " TEXT UNIQUE NOT NULL, " + ConfigurationContract.Configuration.XML + " TEXT NOT NULL, " + ConfigurationContract.Configuration.DELETED +" INTEGER NOT NULL DEFAULT(0))";
private static final String CREATE_CONFIGURATIONS = "CREATE TABLE " + Tables.CONFIGURATIONS
+ "(" + ConfigurationContract.Configuration._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ ConfigurationContract.Configuration.NAME + " TEXT UNIQUE NOT NULL, "
+ ConfigurationContract.Configuration.XML + " TEXT NOT NULL, "
+ ConfigurationContract.Configuration.DELETED +" INTEGER NOT NULL DEFAULT(0))";
private static final String DROP_IF_EXISTS = "DROP TABLE IF EXISTS ";
public SQLiteHelper(Context context) {
SQLiteHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@@ -250,6 +254,7 @@ public class DatabaseHelper {
@Override
public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) {
// This method does nothing for now.
//noinspection SwitchStatementWithTooFewBranches
switch (oldVersion) {
case 1:
// do nothing

View File

@@ -42,8 +42,8 @@ import no.nordicsemi.android.nrftoolbox.wearable.common.Constants;
public class UARTConfigurationSynchronizer {
private static final String WEAR_URI_PREFIX = "wear:"; // no / at the end as the path already has it
private static UARTConfigurationSynchronizer mInstance;
private GoogleApiClient mGoogleApiClient;
private static UARTConfigurationSynchronizer instance;
private GoogleApiClient googleApiClient;
/**
* Initializes the synchronizer.
@@ -51,11 +51,11 @@ public class UARTConfigurationSynchronizer {
* @param listener the connection callbacks listener
*/
public static UARTConfigurationSynchronizer from(final Context context, final GoogleApiClient.ConnectionCallbacks listener) {
if (mInstance == null)
mInstance = new UARTConfigurationSynchronizer();
if (instance == null)
instance = new UARTConfigurationSynchronizer();
mInstance.init(context, listener);
return mInstance;
instance.init(context, listener);
return instance;
}
private UARTConfigurationSynchronizer() {
@@ -63,30 +63,31 @@ public class UARTConfigurationSynchronizer {
}
private void init(final Context context, final GoogleApiClient.ConnectionCallbacks listener) {
if (mGoogleApiClient != null)
if (googleApiClient != null)
return;
mGoogleApiClient = new GoogleApiClient.Builder(context)
googleApiClient = new GoogleApiClient.Builder(context)
.addApiIfAvailable(Wearable.API)
.addConnectionCallbacks(listener)
.build();
mGoogleApiClient.connect();
googleApiClient.connect();
}
/**
* Closes the synchronizer.
*/
public void close() {
if (mGoogleApiClient != null)
mGoogleApiClient.disconnect();
mGoogleApiClient = null;
if (googleApiClient != null)
googleApiClient.disconnect();
googleApiClient = null;
}
/**
* Returns true if Wearable API has been connected.
*/
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
public boolean hasConnectedApi() {
return mGoogleApiClient != null && mGoogleApiClient.isConnected() && mGoogleApiClient.hasConnectedApi(Wearable.API);
return googleApiClient != null && googleApiClient.isConnected() && googleApiClient.hasConnectedApi(Wearable.API);
}
/**
@@ -113,7 +114,7 @@ public class UARTConfigurationSynchronizer {
}
map.putDataMapArrayList(Constants.UART.Configuration.COMMANDS, commands);
final PutDataRequest request = mapRequest.asPutDataRequest();
return Wearable.DataApi.putDataItem(mGoogleApiClient, request);
return Wearable.DataApi.putDataItem(googleApiClient, request);
}
/**
@@ -121,10 +122,11 @@ public class UARTConfigurationSynchronizer {
* Call this when configuration has been deleted.
* @return pending result
*/
@SuppressWarnings("UnusedReturnValue")
public PendingResult<DataApi.DeleteDataItemsResult> onConfigurationDeleted(final long id) {
if (!hasConnectedApi())
return null;
return Wearable.DataApi.deleteDataItems(mGoogleApiClient, id2Uri(id));
return Wearable.DataApi.deleteDataItems(googleApiClient, id2Uri(id));
}
/**

View File

@@ -42,6 +42,7 @@ public class MainWearableListenerService extends WearableListenerService {
// A disconnect message was sent. The information which profile should be disconnected is in the data.
final String profile = new String(messageEvent.getData());
//noinspection SwitchStatementWithTooFewBranches
switch (profile) {
// Currently only UART profile has Wear support
case Constants.UART.PROFILE: {

View File

@@ -41,13 +41,13 @@ public class DividerItemDecoration extends RecyclerView.ItemDecoration {
public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
private Drawable mDivider;
private Drawable divider;
private int mOrientation;
private int orientation;
public DividerItemDecoration(Context context, int orientation) {
final TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);
divider = a.getDrawable(0);
a.recycle();
setOrientation(orientation);
}
@@ -56,12 +56,12 @@ public class DividerItemDecoration extends RecyclerView.ItemDecoration {
if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
throw new IllegalArgumentException("invalid orientation");
}
mOrientation = orientation;
orientation = orientation;
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (mOrientation == VERTICAL_LIST) {
if (orientation == VERTICAL_LIST) {
drawVertical(c, parent);
} else {
drawHorizontal(c, parent);
@@ -78,9 +78,9 @@ public class DividerItemDecoration extends RecyclerView.ItemDecoration {
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int top = child.getBottom() + params.bottomMargin;
final int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
final int bottom = top + divider.getIntrinsicHeight();
divider.setBounds(left, top, right, bottom);
divider.draw(c);
}
}
@@ -94,18 +94,18 @@ public class DividerItemDecoration extends RecyclerView.ItemDecoration {
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int left = child.getRight() + params.rightMargin;
final int right = left + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
final int right = left + divider.getIntrinsicHeight();
divider.setBounds(left, top, right, bottom);
divider.draw(c);
}
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if (mOrientation == VERTICAL_LIST) {
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
if (orientation == VERTICAL_LIST) {
outRect.set(0, 0, 0, divider.getIntrinsicHeight());
} else {
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
outRect.set(0, 0, divider.getIntrinsicWidth(), 0);
}
}
}

View File

@@ -38,9 +38,9 @@ import no.nordicsemi.android.nrftoolbox.R;
public class ForegroundLinearLayout extends LinearLayout {
private Drawable mForegroundSelector;
private Rect mRectPadding;
private boolean mUseBackgroundPadding = false;
private Drawable foregroundSelector;
private Rect rectPadding;
private boolean useBackgroundPadding = false;
public ForegroundLinearLayout(Context context) {
super(context);
@@ -65,9 +65,9 @@ public class ForegroundLinearLayout extends LinearLayout {
if (this.getBackground() instanceof NinePatchDrawable) {
final NinePatchDrawable npd = (NinePatchDrawable) this.getBackground();
mRectPadding = new Rect();
if (npd.getPadding(mRectPadding)) {
mUseBackgroundPadding = true;
rectPadding = new Rect();
if (npd.getPadding(rectPadding)) {
useBackgroundPadding = true;
}
}
}
@@ -76,8 +76,8 @@ public class ForegroundLinearLayout extends LinearLayout {
protected void drawableStateChanged() {
super.drawableStateChanged();
if (mForegroundSelector != null && mForegroundSelector.isStateful()) {
mForegroundSelector.setState(getDrawableState());
if (foregroundSelector != null && foregroundSelector.isStateful()) {
foregroundSelector.setState(getDrawableState());
}
}
@@ -85,11 +85,11 @@ public class ForegroundLinearLayout extends LinearLayout {
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (mForegroundSelector != null) {
if (mUseBackgroundPadding) {
mForegroundSelector.setBounds(mRectPadding.left, mRectPadding.top, w - mRectPadding.right, h - mRectPadding.bottom);
if (foregroundSelector != null) {
if (useBackgroundPadding) {
foregroundSelector.setBounds(rectPadding.left, rectPadding.top, w - rectPadding.right, h - rectPadding.bottom);
} else {
mForegroundSelector.setBounds(0, 0, w, h);
foregroundSelector.setBounds(0, 0, w, h);
}
}
}
@@ -98,30 +98,30 @@ public class ForegroundLinearLayout extends LinearLayout {
protected void dispatchDraw(@NonNull Canvas canvas) {
super.dispatchDraw(canvas);
if (mForegroundSelector != null) {
mForegroundSelector.draw(canvas);
if (foregroundSelector != null) {
foregroundSelector.draw(canvas);
}
}
@Override
protected boolean verifyDrawable(Drawable who) {
return super.verifyDrawable(who) || (who == mForegroundSelector);
return super.verifyDrawable(who) || (who == foregroundSelector);
}
@Override
public void jumpDrawablesToCurrentState() {
super.jumpDrawablesToCurrentState();
if (mForegroundSelector != null) mForegroundSelector.jumpToCurrentState();
if (foregroundSelector != null) foregroundSelector.jumpToCurrentState();
}
public void setForeground(Drawable drawable) {
if (mForegroundSelector != drawable) {
if (mForegroundSelector != null) {
mForegroundSelector.setCallback(null);
unscheduleDrawable(mForegroundSelector);
if (foregroundSelector != drawable) {
if (foregroundSelector != null) {
foregroundSelector.setCallback(null);
unscheduleDrawable(foregroundSelector);
}
mForegroundSelector = drawable;
foregroundSelector = drawable;
if (drawable != null) {
setWillNotDraw(false);
@@ -141,8 +141,8 @@ public class ForegroundLinearLayout extends LinearLayout {
@Override
public void drawableHotspotChanged(float x, float y) {
super.drawableHotspotChanged(x, y);
if (mForegroundSelector != null) {
mForegroundSelector.setHotspot(x, y);
if (foregroundSelector != null) {
foregroundSelector.setHotspot(x, y);
}
}
}

View File

@@ -38,9 +38,9 @@ import no.nordicsemi.android.nrftoolbox.R;
public class ForegroundRelativeLayout extends RelativeLayout {
private Drawable mForegroundSelector;
private Rect mRectPadding;
private boolean mUseBackgroundPadding = false;
private Drawable foregroundSelector;
private Rect rectPadding;
private boolean useBackgroundPadding = false;
public ForegroundRelativeLayout(Context context) {
super(context);
@@ -65,9 +65,9 @@ public class ForegroundRelativeLayout extends RelativeLayout {
if (this.getBackground() instanceof NinePatchDrawable) {
final NinePatchDrawable npd = (NinePatchDrawable) this.getBackground();
mRectPadding = new Rect();
if (npd.getPadding(mRectPadding)) {
mUseBackgroundPadding = true;
rectPadding = new Rect();
if (npd.getPadding(rectPadding)) {
useBackgroundPadding = true;
}
}
}
@@ -76,8 +76,8 @@ public class ForegroundRelativeLayout extends RelativeLayout {
protected void drawableStateChanged() {
super.drawableStateChanged();
if (mForegroundSelector != null && mForegroundSelector.isStateful()) {
mForegroundSelector.setState(getDrawableState());
if (foregroundSelector != null && foregroundSelector.isStateful()) {
foregroundSelector.setState(getDrawableState());
}
}
@@ -85,11 +85,11 @@ public class ForegroundRelativeLayout extends RelativeLayout {
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (mForegroundSelector != null) {
if (mUseBackgroundPadding) {
mForegroundSelector.setBounds(mRectPadding.left, mRectPadding.top, w - mRectPadding.right, h - mRectPadding.bottom);
if (foregroundSelector != null) {
if (useBackgroundPadding) {
foregroundSelector.setBounds(rectPadding.left, rectPadding.top, w - rectPadding.right, h - rectPadding.bottom);
} else {
mForegroundSelector.setBounds(0, 0, w, h);
foregroundSelector.setBounds(0, 0, w, h);
}
}
}
@@ -98,30 +98,30 @@ public class ForegroundRelativeLayout extends RelativeLayout {
protected void dispatchDraw(@NonNull Canvas canvas) {
super.dispatchDraw(canvas);
if (mForegroundSelector != null) {
mForegroundSelector.draw(canvas);
if (foregroundSelector != null) {
foregroundSelector.draw(canvas);
}
}
@Override
protected boolean verifyDrawable(Drawable who) {
return super.verifyDrawable(who) || (who == mForegroundSelector);
return super.verifyDrawable(who) || (who == foregroundSelector);
}
@Override
public void jumpDrawablesToCurrentState() {
super.jumpDrawablesToCurrentState();
if (mForegroundSelector != null) mForegroundSelector.jumpToCurrentState();
if (foregroundSelector != null) foregroundSelector.jumpToCurrentState();
}
public void setForeground(Drawable drawable) {
if (mForegroundSelector != drawable) {
if (mForegroundSelector != null) {
mForegroundSelector.setCallback(null);
unscheduleDrawable(mForegroundSelector);
if (foregroundSelector != drawable) {
if (foregroundSelector != null) {
foregroundSelector.setCallback(null);
unscheduleDrawable(foregroundSelector);
}
mForegroundSelector = drawable;
foregroundSelector = drawable;
if (drawable != null) {
setWillNotDraw(false);
@@ -141,8 +141,8 @@ public class ForegroundRelativeLayout extends RelativeLayout {
@Override
public void drawableHotspotChanged(float x, float y) {
super.drawableHotspotChanged(x, y);
if (mForegroundSelector != null) {
mForegroundSelector.setHotspot(x, y);
if (foregroundSelector != null) {
foregroundSelector.setHotspot(x, y);
}
}
}

View File

@@ -41,19 +41,19 @@ public class DeviceItemLayout extends RelativeLayout implements WearableListView
private static final float SHRINK_LABEL_ALPHA = .5f;
private static final float EXPAND_LABEL_ALPHA = 1f;
private float mExpandCircleRadius;
private float mShrinkCircleRadius;
private float expandCircleRadius;
private float shrinkCircleRadius;
private ObjectAnimator mExpandCircleAnimator;
private ObjectAnimator mFadeInLabelAnimator;
private AnimatorSet mExpandAnimator;
private ObjectAnimator expandCircleAnimator;
private ObjectAnimator fadeInLabelAnimator;
private AnimatorSet expandAnimator;
private ObjectAnimator mShrinkCircleAnimator;
private ObjectAnimator mFadeOutLabelAnimator;
private AnimatorSet mShrinkAnimator;
private ObjectAnimator shrinkCircleAnimator;
private ObjectAnimator fadeOutLabelAnimator;
private AnimatorSet shrinkAnimator;
private TextView mName;
private CircledImageView mIcon;
private TextView name;
private CircledImageView icon;
public DeviceItemLayout(final Context context) {
this(context, null, 0);
@@ -71,51 +71,51 @@ public class DeviceItemLayout extends RelativeLayout implements WearableListView
protected void onFinishInflate() {
super.onFinishInflate();
mName = findViewById(R.id.name);
mIcon = findViewById(R.id.icon);
mExpandCircleRadius = mIcon.getCircleRadius();
mShrinkCircleRadius = mExpandCircleRadius * SHRINK_CIRCLE_RATIO;
name = findViewById(R.id.name);
icon = findViewById(R.id.icon);
expandCircleRadius = icon.getCircleRadius();
shrinkCircleRadius = expandCircleRadius * SHRINK_CIRCLE_RATIO;
mShrinkCircleAnimator = ObjectAnimator.ofFloat(mIcon, "circleRadius", mExpandCircleRadius, mShrinkCircleRadius);
mFadeOutLabelAnimator = ObjectAnimator.ofFloat(mName, "alpha", EXPAND_LABEL_ALPHA, SHRINK_LABEL_ALPHA);
mShrinkAnimator = new AnimatorSet().setDuration(ANIMATION_DURATION_MS);
mShrinkAnimator.playTogether(mShrinkCircleAnimator, mFadeOutLabelAnimator);
shrinkCircleAnimator = ObjectAnimator.ofFloat(icon, "circleRadius", expandCircleRadius, shrinkCircleRadius);
fadeOutLabelAnimator = ObjectAnimator.ofFloat(name, "alpha", EXPAND_LABEL_ALPHA, SHRINK_LABEL_ALPHA);
shrinkAnimator = new AnimatorSet().setDuration(ANIMATION_DURATION_MS);
shrinkAnimator.playTogether(shrinkCircleAnimator, fadeOutLabelAnimator);
mExpandCircleAnimator = ObjectAnimator.ofFloat(mIcon, "circleRadius", mShrinkCircleRadius, mExpandCircleRadius);
mFadeInLabelAnimator = ObjectAnimator.ofFloat(mName, "alpha", SHRINK_LABEL_ALPHA, EXPAND_LABEL_ALPHA);
mExpandAnimator = new AnimatorSet().setDuration(ANIMATION_DURATION_MS);
mExpandAnimator.playTogether(mExpandCircleAnimator, mFadeInLabelAnimator);
expandCircleAnimator = ObjectAnimator.ofFloat(icon, "circleRadius", shrinkCircleRadius, expandCircleRadius);
fadeInLabelAnimator = ObjectAnimator.ofFloat(name, "alpha", SHRINK_LABEL_ALPHA, EXPAND_LABEL_ALPHA);
expandAnimator = new AnimatorSet().setDuration(ANIMATION_DURATION_MS);
expandAnimator.playTogether(expandCircleAnimator, fadeInLabelAnimator);
}
@Override
public void onCenterPosition(final boolean animate) {
if (animate) {
mShrinkAnimator.cancel();
if (!mExpandAnimator.isRunning()) {
mExpandCircleAnimator.setFloatValues(mIcon.getCircleRadius(), mExpandCircleRadius);
mFadeInLabelAnimator.setFloatValues(mName.getAlpha(), EXPAND_LABEL_ALPHA);
mExpandAnimator.start();
shrinkAnimator.cancel();
if (!expandAnimator.isRunning()) {
expandCircleAnimator.setFloatValues(icon.getCircleRadius(), expandCircleRadius);
fadeInLabelAnimator.setFloatValues(name.getAlpha(), EXPAND_LABEL_ALPHA);
expandAnimator.start();
}
} else {
mExpandAnimator.cancel();
mIcon.setCircleRadius(mExpandCircleRadius);
mName.setAlpha(EXPAND_LABEL_ALPHA);
expandAnimator.cancel();
icon.setCircleRadius(expandCircleRadius);
name.setAlpha(EXPAND_LABEL_ALPHA);
}
}
@Override
public void onNonCenterPosition(final boolean animate) {
if (animate) {
mExpandAnimator.cancel();
if (!mShrinkAnimator.isRunning()) {
mShrinkCircleAnimator.setFloatValues(mIcon.getCircleRadius(), mShrinkCircleRadius);
mFadeOutLabelAnimator.setFloatValues(mName.getAlpha(), SHRINK_LABEL_ALPHA);
mShrinkAnimator.start();
expandAnimator.cancel();
if (!shrinkAnimator.isRunning()) {
shrinkCircleAnimator.setFloatValues(icon.getCircleRadius(), shrinkCircleRadius);
fadeOutLabelAnimator.setFloatValues(name.getAlpha(), SHRINK_LABEL_ALPHA);
shrinkAnimator.start();
}
} else {
mShrinkAnimator.cancel();
mIcon.setCircleRadius(mShrinkCircleRadius);
mName.setAlpha(SHRINK_LABEL_ALPHA);
shrinkAnimator.cancel();
icon.setCircleRadius(shrinkCircleRadius);
name.setAlpha(SHRINK_LABEL_ALPHA);
}
}
}

View File

@@ -48,127 +48,127 @@ public class DevicesAdapter extends WearableListView.Adapter {
private final static long SCAN_DURATION = 5000;
private final List<BluetoothDevice> mDevices = new ArrayList<>();
private final LayoutInflater mInflater;
private final Handler mHandler;
private final WearableListView mListView;
private final String mNotAvailable;
private final String mConnectingText;
private final String mAvailableText;
private final String mBondedText;
private final String mBondingText;
private final List<BluetoothDevice> devices = new ArrayList<>();
private final LayoutInflater inflater;
private final Handler handler;
private final WearableListView listView;
private final String notAvailable;
private final String connectingText;
private final String availableText;
private final String bondedText;
private final String bondingText;
/** A position of a device that the activity is currently connecting to. */
private int mConnectingPosition = -1;
private int connectingPosition = -1;
/** Flag set to true when scanner is active. */
private boolean mScanning;
private boolean scanning;
public DevicesAdapter(final WearableListView listView) {
final Context context = listView.getContext();
mInflater = LayoutInflater.from(context);
mNotAvailable = context.getString(R.string.not_available);
mConnectingText = context.getString(R.string.state_connecting);
mAvailableText = context.getString(R.string.devices_list_available);
mBondedText = context.getString(R.string.devices_list_bonded);
mBondingText = context.getString(R.string.devices_list_bonding);
mListView = listView;
mHandler = new Handler();
inflater = LayoutInflater.from(context);
notAvailable = context.getString(R.string.not_available);
connectingText = context.getString(R.string.state_connecting);
availableText = context.getString(R.string.devices_list_available);
bondedText = context.getString(R.string.devices_list_bonded);
bondingText = context.getString(R.string.devices_list_bonding);
this.listView = listView;
handler = new Handler();
final BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter != null)
mDevices.addAll(bluetoothAdapter.getBondedDevices());
devices.addAll(bluetoothAdapter.getBondedDevices());
}
@NonNull
@Override
public WearableListView.ViewHolder onCreateViewHolder(@NonNull final ViewGroup viewGroup, final int position) {
return new ItemViewHolder(mInflater.inflate(R.layout.device_item, viewGroup, false));
return new ItemViewHolder(inflater.inflate(R.layout.device_item, viewGroup, false));
}
@Override
public void onBindViewHolder(@NonNull final WearableListView.ViewHolder holder, final int position) {
final ItemViewHolder viewHolder = (ItemViewHolder) holder;
if (position < mDevices.size()) {
final BluetoothDevice device = mDevices.get(position);
if (position < devices.size()) {
final BluetoothDevice device = devices.get(position);
viewHolder.mDevice = device;
viewHolder.mName.setText(TextUtils.isEmpty(device.getName()) ? mNotAvailable : device.getName());
viewHolder.mAddress.setText(getState(device, position));
viewHolder.mIcon.showIndeterminateProgress(position == mConnectingPosition);
viewHolder.device = device;
viewHolder.name.setText(TextUtils.isEmpty(device.getName()) ? notAvailable : device.getName());
viewHolder.address.setText(getState(device, position));
viewHolder.icon.showIndeterminateProgress(position == connectingPosition);
} else {
viewHolder.mDevice = null;
viewHolder.mName.setText(mScanning ? R.string.devices_list_scanning : R.string.devices_list_start_scan);
viewHolder.mAddress.setText(null);
viewHolder.mIcon.showIndeterminateProgress(mScanning);
viewHolder.device = null;
viewHolder.name.setText(scanning ? R.string.devices_list_scanning : R.string.devices_list_start_scan);
viewHolder.address.setText(null);
viewHolder.icon.showIndeterminateProgress(scanning);
}
}
@Override
public int getItemCount() {
return mDevices.size() + (mConnectingPosition == -1 ? 1 : 0);
return devices.size() + (connectingPosition == -1 ? 1 : 0);
}
public void setConnectingPosition(final int connectingPosition) {
final int oldPosition = mConnectingPosition;
this.mConnectingPosition = connectingPosition;
final int oldPosition = connectingPosition;
this.connectingPosition = connectingPosition;
if (connectingPosition >= 0) {
// The "Scan for nearby device' item is removed
notifyItemChanged(connectingPosition);
notifyItemRemoved(mDevices.size());
notifyItemRemoved(devices.size());
} else {
if (oldPosition >= 0)
notifyItemChanged(oldPosition);
notifyItemInserted(mDevices.size());
notifyItemInserted(devices.size());
}
}
public void startLeScan() {
// Scanning is disabled when we are connecting or connected.
if (mConnectingPosition >= 0)
if (connectingPosition >= 0)
return;
if (mScanning) {
if (scanning) {
// Extend scanning for some time more
mHandler.removeCallbacks(mStopScanTask);
mHandler.postDelayed(mStopScanTask, SCAN_DURATION);
handler.removeCallbacks(stopScanTask);
handler.postDelayed(stopScanTask, SCAN_DURATION);
return;
}
final BluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();
final ScanSettings settings = new ScanSettings.Builder().setReportDelay(1000).setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();
scanner.startScan(null, settings, mScanCallback);
scanner.startScan(null, settings, scanCallback);
// Setup timer that will stop scanning
mHandler.postDelayed(mStopScanTask, SCAN_DURATION);
mScanning = true;
notifyItemChanged(mDevices.size());
handler.postDelayed(stopScanTask, SCAN_DURATION);
scanning = true;
notifyItemChanged(devices.size());
}
public void stopLeScan() {
if (!mScanning)
if (!scanning)
return;
final BluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();
scanner.stopScan(mScanCallback);
scanner.stopScan(scanCallback);
mHandler.removeCallbacks(mStopScanTask);
mScanning = false;
notifyItemChanged(mDevices.size());
handler.removeCallbacks(stopScanTask);
scanning = false;
notifyItemChanged(devices.size());
}
private String getState(final BluetoothDevice device, final int position) {
if (mConnectingPosition == position)
return mConnectingText;
if (connectingPosition == position)
return connectingText;
else if (device.getBondState() == BluetoothDevice.BOND_BONDED)
return mBondedText;
return bondedText;
else if (device.getBondState() == BluetoothDevice.BOND_BONDING)
return mBondingText;
return mAvailableText;
return bondingText;
return availableText;
}
private Runnable mStopScanTask = this::stopLeScan;
private Runnable stopScanTask = this::stopLeScan;
private ScanCallback mScanCallback = new ScanCallback() {
private ScanCallback scanCallback = new ScanCallback() {
@Override
public void onScanResult(final int callbackType, @NonNull final ScanResult result) {
// empty
@@ -176,16 +176,16 @@ public class DevicesAdapter extends WearableListView.Adapter {
@Override
public void onBatchScanResults(final List<ScanResult> results) {
final int size = mDevices.size();
final int size = devices.size();
for (final ScanResult result : results) {
final BluetoothDevice device = result.getDevice();
if (!mDevices.contains(device))
mDevices.add(device);
if (!devices.contains(device))
devices.add(device);
}
if (size != mDevices.size()) {
notifyItemRangeInserted(size, mDevices.size() - size);
if (size != devices.size()) {
notifyItemRangeInserted(size, devices.size() - size);
if (size == 0)
mListView.scrollToPosition(0);
listView.scrollToPosition(0);
}
}
@@ -196,22 +196,22 @@ public class DevicesAdapter extends WearableListView.Adapter {
};
public static class ItemViewHolder extends WearableListView.ViewHolder {
private CircledImageView mIcon;
private TextView mName;
private TextView mAddress;
private BluetoothDevice mDevice;
private CircledImageView icon;
private TextView name;
private TextView address;
private BluetoothDevice device;
public ItemViewHolder(final View itemView) {
super(itemView);
mIcon = itemView.findViewById(R.id.icon);
mName = itemView.findViewById(R.id.name);
mAddress = itemView.findViewById(R.id.state);
icon = itemView.findViewById(R.id.icon);
name = itemView.findViewById(R.id.name);
address = itemView.findViewById(R.id.state);
}
/** Returns the Bluetooth device for that holder, or null for "Scanning for nearby devices" row. */
public BluetoothDevice getDevice() {
return mDevice;
return device;
}
}
}

View File

@@ -45,10 +45,10 @@ public class ScannerActivity extends Activity {
private static final int PERMISSION_REQUEST_LOCATION = 1;
private DevicesAdapter mDeviceAdapter;
private View mHeader;
private DevicesAdapter deviceAdapter;
private View header;
private BroadcastReceiver mServiceBroadcastReceiver = new BroadcastReceiver() {
private BroadcastReceiver serviceBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
final String action = intent.getAction();
@@ -57,7 +57,7 @@ public class ScannerActivity extends Activity {
case BleProfileService.BROADCAST_CONNECTION_STATE: {
final int state = intent.getIntExtra(BleProfileService.EXTRA_CONNECTION_STATE, BleProfileService.STATE_DISCONNECTED);
if (state == BleProfileService.STATE_DISCONNECTED)
mDeviceAdapter.setConnectingPosition(-1);
deviceAdapter.setConnectingPosition(-1);
break;
}
case BleProfileService.BROADCAST_DEVICE_READY: {
@@ -68,7 +68,7 @@ public class ScannerActivity extends Activity {
}
case BleProfileService.BROADCAST_DEVICE_NOT_SUPPORTED: {
Toast.makeText(ScannerActivity.this, R.string.devices_list_device_not_supported, Toast.LENGTH_SHORT).show();
mDeviceAdapter.setConnectingPosition(-1);
deviceAdapter.setConnectingPosition(-1);
break;
}
case BleProfileService.BROADCAST_ERROR: {
@@ -79,7 +79,7 @@ public class ScannerActivity extends Activity {
break;
}
case BleProfileService.BROADCAST_BOND_STATE: {
mDeviceAdapter.notifyDataSetChanged(); // TODO check this. Bonding was never tested.
deviceAdapter.notifyDataSetChanged(); // TODO check this. Bonding was never tested.
break;
}
}
@@ -93,21 +93,21 @@ public class ScannerActivity extends Activity {
// Get the list component from the layout of the activity
final WearableListView listView = findViewById(R.id.devices_list);
listView.setAdapter(mDeviceAdapter = new DevicesAdapter(listView));
listView.setClickListener(mOnRowClickListener);
listView.addOnScrollListener(mOnScrollListener);
listView.setAdapter(deviceAdapter = new DevicesAdapter(listView));
listView.setClickListener(onRowClickListener);
listView.addOnScrollListener(onScrollListener);
// The header will be moved as the list is scrolled
mHeader = findViewById(R.id.header);
header = findViewById(R.id.header);
// Register a broadcast receiver that will listen for events from the service.
LocalBroadcastManager.getInstance(this).registerReceiver(mServiceBroadcastReceiver, BleProfileService.makeIntentFilter());
LocalBroadcastManager.getInstance(this).registerReceiver(serviceBroadcastReceiver, BleProfileService.makeIntentFilter());
}
@Override
protected void onDestroy() {
super.onDestroy();
LocalBroadcastManager.getInstance(this).unregisterReceiver(mServiceBroadcastReceiver);
LocalBroadcastManager.getInstance(this).unregisterReceiver(serviceBroadcastReceiver);
}
@Override
@@ -115,7 +115,7 @@ public class ScannerActivity extends Activity {
switch (requestCode) {
case PERMISSION_REQUEST_LOCATION:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
mDeviceAdapter.startLeScan();
deviceAdapter.startLeScan();
} else {
Toast.makeText(ScannerActivity.this, "Location permission required", Toast.LENGTH_SHORT).show();
finish();
@@ -134,32 +134,32 @@ public class ScannerActivity extends Activity {
return;
}
}
mDeviceAdapter.startLeScan();
deviceAdapter.startLeScan();
}
@Override
protected void onPause() {
super.onPause();
mDeviceAdapter.stopLeScan();
deviceAdapter.stopLeScan();
}
/** List click listener. */
private WearableListView.ClickListener mOnRowClickListener = new WearableListView.ClickListener() {
private WearableListView.ClickListener onRowClickListener = new WearableListView.ClickListener() {
@Override
public void onClick(final WearableListView.ViewHolder holder) {
final DevicesAdapter.ItemViewHolder viewHolder = (DevicesAdapter.ItemViewHolder) holder;
final BluetoothDevice device = viewHolder.getDevice();
if (device != null) {
mDeviceAdapter.stopLeScan();
mDeviceAdapter.setConnectingPosition(holder.getAdapterPosition());
deviceAdapter.stopLeScan();
deviceAdapter.setConnectingPosition(holder.getAdapterPosition());
// Start the service that will connect to selected device
final Intent service = new Intent(ScannerActivity.this, BleProfileService.class);
service.putExtra(BleProfileService.EXTRA_DEVICE_ADDRESS, device.getAddress());
startService(service);
} else {
mDeviceAdapter.startLeScan();
deviceAdapter.startLeScan();
}
}
@@ -170,13 +170,13 @@ public class ScannerActivity extends Activity {
};
/** The following code ensures that the title scrolls as the user scrolls up or down the list/ */
private WearableListView.OnScrollListener mOnScrollListener = new WearableListView.OnScrollListener() {
private WearableListView.OnScrollListener onScrollListener = new WearableListView.OnScrollListener() {
@Override
public void onAbsoluteScrollChange(final int i) {
if (i > 0)
mHeader.setY(-i);
header.setY(-i);
else
mHeader.setY(0);
header.setY(0);
}
@Override

View File

@@ -76,37 +76,37 @@ public class BleManager implements BleProfileApi {
private final static UUID GENERIC_ATTRIBUTE_SERVICE = UUID.fromString("00001801-0000-1000-8000-00805f9b34fb");
private final static UUID SERVICE_CHANGED_CHARACTERISTIC = UUID.fromString("00002A05-0000-1000-8000-00805f9b34fb");
private final Object mLock = new Object();
private final Object lock = new Object();
protected final BleManagerCallbacks mCallbacks;
private final Context mContext;
private final Handler mHandler;
protected BluetoothDevice mBluetoothDevice;
protected BleProfile mProfile;
private BluetoothGatt mBluetoothGatt;
private BleManagerGattCallback mGattCallback;
protected final BleManagerCallbacks callbacks;
private final Context context;
private final Handler handler;
protected BluetoothDevice bluetoothDevice;
protected BleProfile profile;
private BluetoothGatt bluetoothGatt;
private BleManagerGattCallback gattCallback;
/**
* This flag is set to false only when the {@link #shouldAutoConnect()} method returns true and the device got disconnected without calling {@link #disconnect()} method.
* If {@link #shouldAutoConnect()} returns false (default) this is always set to true.
*/
private boolean mUserDisconnected;
private boolean userDisconnected;
/**
* Flag set to true when {@link #shouldAutoConnect()} method returned <code>true</code>. The first connection attempt is done with <code>autoConnect</code>
* flag set to false (to make the first connection quick) but on connection lost the manager will call {@link #connect(BluetoothDevice)} again.
* This time this method will call {@link BluetoothGatt#connect()} which always uses <code>autoConnect</code> equal true.
*/
private boolean mInitialConnection;
private boolean initialConnection;
/** Flag set to true when the device is connected. */
private boolean mConnected;
private int mConnectionState = BluetoothGatt.STATE_DISCONNECTED;
private boolean connected;
private int connectionState = BluetoothGatt.STATE_DISCONNECTED;
/** Last received battery value or -1 if value wasn't received. */
private int mBatteryValue = -1;
private int batteryValue = -1;
/**
* The current MTU (Maximum Transfer Unit). The maximum number of bytes that can be sent in a single packet is MTU-3.
*/
private int mMtu = 23;
private int mtu = 23;
private final BroadcastReceiver mBluetoothStateBroadcastReceiver = new BroadcastReceiver() {
private final BroadcastReceiver bluetoothStateBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF);
@@ -115,9 +115,9 @@ public class BleManager implements BleProfileApi {
switch (state) {
case BluetoothAdapter.STATE_TURNING_OFF:
case BluetoothAdapter.STATE_OFF:
if (mConnected && previousState != BluetoothAdapter.STATE_TURNING_OFF && previousState != BluetoothAdapter.STATE_OFF) {
if (connected && previousState != BluetoothAdapter.STATE_TURNING_OFF && previousState != BluetoothAdapter.STATE_OFF) {
// The connection is killed by the system, no need to gently disconnect
mGattCallback.notifyDeviceDisconnected(mBluetoothDevice);
gattCallback.notifyDeviceDisconnected(bluetoothDevice);
}
close();
break;
@@ -125,7 +125,7 @@ public class BleManager implements BleProfileApi {
}
};
private BroadcastReceiver mBondingBroadcastReceiver = new BroadcastReceiver() {
private BroadcastReceiver bondingBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
@@ -133,40 +133,40 @@ public class BleManager implements BleProfileApi {
final int previousBondState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, -1);
// Skip other devices
if (mBluetoothGatt == null || !device.getAddress().equals(mBluetoothGatt.getDevice().getAddress()))
if (bluetoothGatt == null || !device.getAddress().equals(bluetoothGatt.getDevice().getAddress()))
return;
DebugLogger.i(TAG, "Bond state changed for: " + device.getName() + " new state: " + bondState + " previous: " + previousBondState);
switch (bondState) {
case BluetoothDevice.BOND_BONDING:
mCallbacks.onBondingRequired(device);
callbacks.onBondingRequired(device);
break;
case BluetoothDevice.BOND_BONDED:
mCallbacks.onBonded(device);
callbacks.onBonded(device);
// Start initializing again.
// In fact, bonding forces additional, internal service discovery (at least on Nexus devices), so this method may safely be used to start this process again.
mBluetoothGatt.discoverServices();
bluetoothGatt.discoverServices();
break;
}
}
};
public BleManager(final Context context, final BleManagerCallbacks callbacks) {
mCallbacks = callbacks;
mContext = context;
mHandler = new Handler();
this.callbacks = callbacks;
this.context = context;
this.handler = new Handler();
// Register bonding broadcast receiver
context.registerReceiver(mBondingBroadcastReceiver, new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED));
context.registerReceiver(bondingBroadcastReceiver, new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED));
}
/**
* Returns the Profile API. Profile may be null if service discovery has not been performed or the device does not match any profile.
*/
public BleProfile getProfile() {
return mProfile;
return profile;
}
/**
@@ -176,7 +176,7 @@ public class BleManager implements BleProfileApi {
*/
@Override
public Context getContext() {
return mContext;
return context;
}
/**
@@ -207,11 +207,11 @@ public class BleManager implements BleProfileApi {
* @param device a device to connect to
*/
public void connect(final BluetoothDevice device) {
if (mConnected)
if (connected)
return;
synchronized (mLock) {
if (mBluetoothGatt != null) {
synchronized (lock) {
if (bluetoothGatt != null) {
// There are 2 ways of reconnecting to the same device:
// 1. Reusing the same BluetoothGatt object and calling connect() - this will force the autoConnect flag to true
// 2. Closing it and reopening a new instance of BluetoothGatt object.
@@ -219,9 +219,9 @@ public class BleManager implements BleProfileApi {
// device.connectGatt(...) can't be called immediately or service discovery
// may never finish on some older devices (Nexus 4, Android 5.0.1).
// If shouldAutoConnect() method returned false we can't call gatt.connect() and have to close gatt and open it again.
if (!mInitialConnection) {
mBluetoothGatt.close();
mBluetoothGatt = null;
if (!initialConnection) {
bluetoothGatt.close();
bluetoothGatt = null;
try {
Thread.sleep(200); // Is 200 ms enough?
} catch (final InterruptedException e) {
@@ -230,29 +230,29 @@ public class BleManager implements BleProfileApi {
} else {
// Instead, the gatt.connect() method will be used to reconnect to the same device.
// This method forces autoConnect = true even if the gatt was created with this flag set to false.
mInitialConnection = false;
mConnectionState = BluetoothGatt.STATE_CONNECTING;
mCallbacks.onDeviceConnecting(device);
mBluetoothGatt.connect();
initialConnection = false;
connectionState = BluetoothGatt.STATE_CONNECTING;
callbacks.onDeviceConnecting(device);
bluetoothGatt.connect();
return;
}
} else {
// Register bonding broadcast receiver
mContext.registerReceiver(mBluetoothStateBroadcastReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
mContext.registerReceiver(mBondingBroadcastReceiver, new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED));
context.registerReceiver(bluetoothStateBroadcastReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
context.registerReceiver(bondingBroadcastReceiver, new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED));
}
}
final boolean shouldAutoConnect = shouldAutoConnect();
mUserDisconnected = !shouldAutoConnect; // We will receive Linkloss events only when the device is connected with autoConnect=true
userDisconnected = !shouldAutoConnect; // We will receive Linkloss events only when the device is connected with autoConnect=true
// The first connection will always be done with autoConnect = false to make the connection quick.
// If the shouldAutoConnect() method returned true, the manager will automatically try to reconnect to this device on link loss.
if (shouldAutoConnect)
mInitialConnection = true;
mBluetoothDevice = device;
mConnectionState = BluetoothGatt.STATE_CONNECTING;
mCallbacks.onDeviceConnecting(device);
mBluetoothGatt = device.connectGatt(mContext, false, mGattCallback = new BleManagerGattCallback());
initialConnection = true;
bluetoothDevice = device;
connectionState = BluetoothGatt.STATE_CONNECTING;
callbacks.onDeviceConnecting(device);
bluetoothGatt = device.connectGatt(context, false, gattCallback = new BleManagerGattCallback());
}
/**
@@ -260,19 +260,19 @@ public class BleManager implements BleProfileApi {
* @return true if device is to be disconnected. False if it was already disconnected.
*/
public boolean disconnect() {
mUserDisconnected = true;
mInitialConnection = false;
userDisconnected = true;
initialConnection = false;
if (mBluetoothGatt != null) {
mConnectionState = BluetoothGatt.STATE_DISCONNECTING;
mCallbacks.onDeviceDisconnecting(mBluetoothGatt.getDevice());
final boolean wasConnected = mConnected;
mBluetoothGatt.disconnect();
if (bluetoothGatt != null) {
connectionState = BluetoothGatt.STATE_DISCONNECTING;
callbacks.onDeviceDisconnecting(bluetoothGatt.getDevice());
final boolean wasConnected = connected;
bluetoothGatt.disconnect();
if (!wasConnected) {
// There will be no callback, the connection attempt will be stopped
mConnectionState = BluetoothGatt.STATE_DISCONNECTED;
mCallbacks.onDeviceDisconnected(mBluetoothGatt.getDevice());
connectionState = BluetoothGatt.STATE_DISCONNECTED;
callbacks.onDeviceDisconnected(bluetoothGatt.getDevice());
}
return true;
}
@@ -283,7 +283,7 @@ public class BleManager implements BleProfileApi {
* This method returns true if the device is connected. Services could have not been discovered yet.
*/
public boolean isConnected() {
return mConnected;
return connected;
}
/**
@@ -295,7 +295,7 @@ public class BleManager implements BleProfileApi {
* @return the connection state
*/
public int getConnectionState() {
return mConnectionState;
return connectionState;
}
/**
@@ -303,7 +303,7 @@ public class BleManager implements BleProfileApi {
* @return the last battery level value in percent
*/
public int getBatteryValue() {
return mBatteryValue;
return batteryValue;
}
/**
@@ -311,21 +311,21 @@ public class BleManager implements BleProfileApi {
*/
public void close() {
try {
mContext.unregisterReceiver(mBluetoothStateBroadcastReceiver);
mContext.unregisterReceiver(mBondingBroadcastReceiver);
context.unregisterReceiver(bluetoothStateBroadcastReceiver);
context.unregisterReceiver(bondingBroadcastReceiver);
} catch (Exception e) {
// the receiver must have been not registered or unregistered before
}
synchronized (mLock) {
if (mBluetoothGatt != null) {
mBluetoothGatt.close();
mBluetoothGatt = null;
synchronized (lock) {
if (bluetoothGatt != null) {
bluetoothGatt.close();
bluetoothGatt = null;
}
mConnected = false;
mInitialConnection = false;
mConnectionState = BluetoothGatt.STATE_DISCONNECTED;
mGattCallback = null;
mBluetoothDevice = null;
connected = false;
initialConnection = false;
connectionState = BluetoothGatt.STATE_DISCONNECTED;
gattCallback = null;
bluetoothDevice = null;
}
}
@@ -341,7 +341,7 @@ public class BleManager implements BleProfileApi {
* @return true if pairing has started, false if it was already paired or an immediate error occur.
*/
private boolean internalCreateBond() {
final BluetoothDevice device = mBluetoothDevice;
final BluetoothDevice device = bluetoothDevice;
if (device == null)
return false;
@@ -359,7 +359,7 @@ public class BleManager implements BleProfileApi {
* the Service Changed characteristic or this characteristic does not have the CCCD.
*/
private boolean ensureServiceChangedEnabled() {
final BluetoothGatt gatt = mBluetoothGatt;
final BluetoothGatt gatt = bluetoothGatt;
if (gatt == null)
return false;
@@ -385,7 +385,7 @@ public class BleManager implements BleProfileApi {
}
private boolean internalEnableNotifications(final BluetoothGattCharacteristic characteristic) {
final BluetoothGatt gatt = mBluetoothGatt;
final BluetoothGatt gatt = bluetoothGatt;
if (gatt == null || characteristic == null)
return false;
@@ -409,7 +409,7 @@ public class BleManager implements BleProfileApi {
}
private boolean internalEnableIndications(final BluetoothGattCharacteristic characteristic) {
final BluetoothGatt gatt = mBluetoothGatt;
final BluetoothGatt gatt = bluetoothGatt;
if (gatt == null || characteristic == null)
return false;
@@ -433,7 +433,7 @@ public class BleManager implements BleProfileApi {
}
private boolean internalReadCharacteristic(final BluetoothGattCharacteristic characteristic) {
final BluetoothGatt gatt = mBluetoothGatt;
final BluetoothGatt gatt = bluetoothGatt;
if (gatt == null || characteristic == null)
return false;
@@ -451,7 +451,7 @@ public class BleManager implements BleProfileApi {
}
private boolean internalWriteCharacteristic(final BluetoothGattCharacteristic characteristic) {
final BluetoothGatt gatt = mBluetoothGatt;
final BluetoothGatt gatt = bluetoothGatt;
if (gatt == null || characteristic == null)
return false;
@@ -469,7 +469,7 @@ public class BleManager implements BleProfileApi {
}
private boolean internalReadDescriptor(final BluetoothGattDescriptor descriptor) {
final BluetoothGatt gatt = mBluetoothGatt;
final BluetoothGatt gatt = bluetoothGatt;
if (gatt == null || descriptor == null)
return false;
@@ -482,7 +482,7 @@ public class BleManager implements BleProfileApi {
}
private boolean internalWriteDescriptor(final BluetoothGattDescriptor descriptor) {
final BluetoothGatt gatt = mBluetoothGatt;
final BluetoothGatt gatt = bluetoothGatt;
if (gatt == null || descriptor == null)
return false;
@@ -495,7 +495,7 @@ public class BleManager implements BleProfileApi {
}
private boolean internalReadBatteryLevel() {
final BluetoothGatt gatt = mBluetoothGatt;
final BluetoothGatt gatt = bluetoothGatt;
if (gatt == null)
return false;
@@ -524,7 +524,7 @@ public class BleManager implements BleProfileApi {
}
private boolean internalSetBatteryNotifications(final boolean enable) {
final BluetoothGatt gatt = mBluetoothGatt;
final BluetoothGatt gatt = bluetoothGatt;
if (gatt == null) {
return false;
}
@@ -566,7 +566,7 @@ public class BleManager implements BleProfileApi {
* @return the result of {@link BluetoothGatt#writeDescriptor(BluetoothGattDescriptor)}
*/
private boolean internalWriteDescriptorWorkaround(final BluetoothGattDescriptor descriptor) {
final BluetoothGatt gatt = mBluetoothGatt;
final BluetoothGatt gatt = bluetoothGatt;
if (gatt == null || descriptor == null)
return false;
@@ -585,18 +585,19 @@ public class BleManager implements BleProfileApi {
@Override
public final int getMtu() {
return mMtu;
return mtu;
}
@Override
public final void overrideMtu(final int mtu) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
mMtu = mtu;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
BleManager.this.mtu = mtu;
}
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private boolean internalRequestMtu(final int mtu) {
final BluetoothGatt gatt = mBluetoothGatt;
final BluetoothGatt gatt = bluetoothGatt;
if (gatt == null)
return false;
@@ -605,12 +606,13 @@ public class BleManager implements BleProfileApi {
@Override
public final boolean requestConnectionPriority(final int priority) {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && enqueue(Request.newConnectionPriorityRequest(priority));
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
&& enqueue(Request.newConnectionPriorityRequest(priority));
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private boolean internalRequestConnectionPriority(final int priority) {
final BluetoothGatt gatt = mBluetoothGatt;
final BluetoothGatt gatt = bluetoothGatt;
if (gatt == null)
return false;
@@ -619,10 +621,10 @@ public class BleManager implements BleProfileApi {
@Override
public boolean enqueue(final Request request) {
if (mGattCallback != null) {
if (gattCallback != null) {
// Add the new task to the end of the queue
mGattCallback.mTaskQueue.add(request);
mGattCallback.nextRequest();
gattCallback.taskQueue.add(request);
gattCallback.nextRequest();
return true;
}
return false;
@@ -639,10 +641,10 @@ public class BleManager implements BleProfileApi {
private final static String ERROR_MTU_REQUEST = "Error on mtu request";
private final static String ERROR_CONNECTION_PRIORITY_REQUEST = "Error on connection priority request";
private final Queue<Request> mTaskQueue = new LinkedList<>();
private Deque<Request> mInitQueue;
private boolean mInitInProgress;
private boolean mOperationInProgress = true;
private final Queue<Request> taskQueue = new LinkedList<>();
private Deque<Request> initQueue;
private boolean initInProgress;
private boolean operationInProgress = true;
/**
* This flag is required to resume operations after the connection priority request was made.
* It is used only on Android Oreo and newer, as only there there is onConnectionUpdated callback.
@@ -650,36 +652,36 @@ public class BleManager implements BleProfileApi {
* when such request wasn't made, this flag ensures the nextRequest() method won't be called
* during another operation.
*/
private boolean mConnectionPriorityOperationInProgress = false;
private boolean connectionPriorityOperationInProgress = false;
private void notifyDeviceDisconnected(final BluetoothDevice device) {
mConnected = false;
mConnectionState = BluetoothGatt.STATE_DISCONNECTED;
if (mUserDisconnected) {
mCallbacks.onDeviceDisconnected(device);
connected = false;
connectionState = BluetoothGatt.STATE_DISCONNECTED;
if (userDisconnected) {
callbacks.onDeviceDisconnected(device);
close();
} else {
mCallbacks.onLinklossOccurred(device);
callbacks.onLinklossOccurred(device);
// We are not closing the connection here as the device should try to reconnect automatically.
// This may be only called when the shouldAutoConnect() method returned true.
}
if (mProfile != null)
mProfile.release();
if (profile != null)
profile.release();
}
private void onError(final BluetoothDevice device, final String message, final int errorCode) {
mCallbacks.onError(device, message, errorCode);
if (mProfile != null)
mProfile.onError(message, errorCode);
callbacks.onError(device, message, errorCode);
if (profile != null)
profile.onError(message, errorCode);
}
@Override
public final void onConnectionStateChange(final BluetoothGatt gatt, final int status, final int newState) {
if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED) {
// Notify the parent activity/service
mConnected = true;
mConnectionState = BluetoothGatt.STATE_CONNECTED;
mCallbacks.onDeviceConnected(gatt.getDevice());
connected = true;
connectionState = BluetoothGatt.STATE_CONNECTED;
callbacks.onDeviceConnected(gatt.getDevice());
/*
* The onConnectionStateChange event is triggered just after the Android connects to a device.
@@ -699,7 +701,7 @@ public class BleManager implements BleProfileApi {
*/
final boolean bonded = gatt.getDevice().getBondState() == BluetoothDevice.BOND_BONDED;
final int delay = bonded ? 1600 : 0; // around 1600 ms is required when connection interval is ~45ms.
mHandler.postDelayed(() -> {
handler.postDelayed(() -> {
// Some proximity tags (e.g. nRF PROXIMITY) initialize bonding automatically when connected.
if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_BONDING) {
gatt.discoverServices();
@@ -707,16 +709,16 @@ public class BleManager implements BleProfileApi {
}, delay);
} else {
if (newState == BluetoothProfile.STATE_DISCONNECTED) {
mOperationInProgress = true; // no more calls are possible
mInitQueue = null;
mTaskQueue.clear();
final boolean wasConnected = mConnected;
// if (mConnected) { // Checking mConnected prevents from calling onDeviceDisconnected if connection attempt failed. This check is not necessary
notifyDeviceDisconnected(gatt.getDevice()); // This sets the mConnected flag to false
operationInProgress = true; // no more calls are possible
initQueue = null;
taskQueue.clear();
final boolean wasConnected = connected;
// if (connected) { // Checking connected prevents from calling onDeviceDisconnected if connection attempt failed. This check is not necessary
notifyDeviceDisconnected(gatt.getDevice()); // This sets the connected flag to false
// }
// Try to reconnect if the initial connection was lost because of a link loss or timeout, and shouldAutoConnect() returned true during connection attempt.
// This time it will set the autoConnect flag to true (gatt.connect() forces autoConnect true)
if (mInitialConnection) {
if (initialConnection) {
connect(gatt.getDevice());
}
@@ -725,7 +727,7 @@ public class BleManager implements BleProfileApi {
}
// TODO Should the disconnect method be called or the connection is still valid? Does this ever happen?
mProfile.onError(ERROR_CONNECTION_STATE_CHANGE, status);
profile.onError(ERROR_CONNECTION_STATE_CHANGE, status);
}
}
@@ -735,31 +737,31 @@ public class BleManager implements BleProfileApi {
final BleProfile profile = BleProfileProvider.findProfile(gatt);
if (profile != null) {
profile.setApi(BleManager.this);
mProfile = profile;
BleManager.this.profile = profile;
// Obtain the queue of initialization requests
mInitInProgress = true;
mInitQueue = profile.initGatt(gatt);
initInProgress = true;
initQueue = profile.initGatt(gatt);
// Before we start executing the initialization queue some other tasks need to be done.
if (mInitQueue == null)
mInitQueue = new LinkedList<>();
if (initQueue == null)
initQueue = new LinkedList<>();
// Note, that operations are added in reverse order to the front of the queue.
// 3. Enable Battery Level notifications if required (if this char. does not exist, this operation will be skipped)
if (mCallbacks.shouldEnableBatteryLevelNotifications(gatt.getDevice()))
mInitQueue.addFirst(Request.newEnableBatteryLevelNotificationsRequest());
if (callbacks.shouldEnableBatteryLevelNotifications(gatt.getDevice()))
initQueue.addFirst(Request.newEnableBatteryLevelNotificationsRequest());
// 2. Read Battery Level characteristic (if such does not exist, this will be skipped)
mInitQueue.addFirst(Request.newReadBatteryLevelRequest());
initQueue.addFirst(Request.newReadBatteryLevelRequest());
// 1. On devices running Android 4.3-6.0 the Service Changed characteristic needs to be enabled by the app (for bonded devices)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N)
mInitQueue.addFirst(Request.newEnableServiceChangedIndicationsRequest());
initQueue.addFirst(Request.newEnableServiceChangedIndicationsRequest());
mOperationInProgress = false;
operationInProgress = false;
nextRequest();
} else {
mCallbacks.onDeviceNotSupported(gatt.getDevice());
callbacks.onDeviceNotSupported(gatt.getDevice());
disconnect();
}
} else {
@@ -773,13 +775,13 @@ public class BleManager implements BleProfileApi {
if (status == BluetoothGatt.GATT_SUCCESS) {
if (isBatteryLevelCharacteristic(characteristic)) {
final int batteryValue = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0);
mBatteryValue = batteryValue;
mProfile.onBatteryValueReceived(gatt, batteryValue);
BleManager.this.batteryValue = batteryValue;
profile.onBatteryValueReceived(gatt, batteryValue);
} else {
// The value has been read. Notify the profile and proceed with the initialization queue.
mProfile.onCharacteristicRead(gatt, characteristic);
profile.onCharacteristicRead(gatt, characteristic);
}
mOperationInProgress = false;
operationInProgress = false;
nextRequest();
} else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_NONE) {
@@ -797,8 +799,8 @@ public class BleManager implements BleProfileApi {
public final void onCharacteristicWrite(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic, final int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
// The value has been written. Notify the profile and proceed with the initialization queue.
mProfile.onCharacteristicWrite(gatt, characteristic);
mOperationInProgress = false;
profile.onCharacteristicWrite(gatt, characteristic);
operationInProgress = false;
nextRequest();
} else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_NONE) {
@@ -816,8 +818,8 @@ public class BleManager implements BleProfileApi {
public void onDescriptorRead(final BluetoothGatt gatt, final BluetoothGattDescriptor descriptor, final int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
// The value has been read. Notify the profile and proceed with the initialization queue.
mProfile.onDescriptorRead(gatt, descriptor);
mOperationInProgress = false;
profile.onDescriptorRead(gatt, descriptor);
operationInProgress = false;
nextRequest();
} else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_NONE) {
@@ -835,8 +837,8 @@ public class BleManager implements BleProfileApi {
public final void onDescriptorWrite(final BluetoothGatt gatt, final BluetoothGattDescriptor descriptor, final int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
// The value has been written. Notify the profile and proceed with the initialization queue.
mProfile.onDescriptorWrite(gatt, descriptor);
mOperationInProgress = false;
profile.onDescriptorWrite(gatt, descriptor);
operationInProgress = false;
nextRequest();
} else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_NONE) {
@@ -854,16 +856,16 @@ public class BleManager implements BleProfileApi {
public final void onCharacteristicChanged(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
if (isBatteryLevelCharacteristic(characteristic)) {
final int batteryValue = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0);
mBatteryValue = batteryValue;
mProfile.onBatteryValueReceived(gatt, batteryValue);
BleManager.this.batteryValue = batteryValue;
profile.onBatteryValueReceived(gatt, batteryValue);
} else {
final BluetoothGattDescriptor cccd = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID);
final boolean notifications = cccd == null || cccd.getValue() == null || cccd.getValue().length != 2 || cccd.getValue()[0] == 0x01;
if (notifications) {
mProfile.onCharacteristicNotified(gatt, characteristic);
profile.onCharacteristicNotified(gatt, characteristic);
} else { // indications
mProfile.onCharacteristicIndicated(gatt, characteristic);
profile.onCharacteristicIndicated(gatt, characteristic);
}
}
}
@@ -871,12 +873,12 @@ public class BleManager implements BleProfileApi {
@Override
public void onMtuChanged(final BluetoothGatt gatt, final int mtu, final int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
mProfile.onMtuChanged(mtu);
profile.onMtuChanged(mtu);
} else {
DebugLogger.e(TAG, "onMtuChanged error: " + status + ", mtu: " + mtu);
onError(gatt.getDevice(), ERROR_MTU_REQUEST, status);
}
mOperationInProgress = false;
operationInProgress = false;
nextRequest();
}
@@ -896,16 +898,16 @@ public class BleManager implements BleProfileApi {
*/
public void onConnectionUpdated(final BluetoothGatt gatt, final int interval, final int latency, final int timeout, final int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
mProfile.onConnectionUpdated(interval, latency, timeout);
profile.onConnectionUpdated(interval, latency, timeout);
} else if (status == 0x3b) { // HCI_ERR_UNACCEPT_CONN_INTERVAL
DebugLogger.e(TAG, "onConnectionUpdated received status: Unacceptable connection interval, interval: " + interval + ", latency: " + latency + ", timeout: " + timeout);
} else {
DebugLogger.e(TAG, "onConnectionUpdated received status: " + status + ", interval: " + interval + ", latency: " + latency + ", timeout: " + timeout);
mCallbacks.onError(gatt.getDevice(), ERROR_CONNECTION_PRIORITY_REQUEST, status);
callbacks.onError(gatt.getDevice(), ERROR_CONNECTION_PRIORITY_REQUEST, status);
}
if (mConnectionPriorityOperationInProgress) {
mConnectionPriorityOperationInProgress = false;
mOperationInProgress = false;
if (connectionPriorityOperationInProgress) {
connectionPriorityOperationInProgress = false;
operationInProgress = false;
nextRequest();
}
}
@@ -915,28 +917,28 @@ public class BleManager implements BleProfileApi {
* the {@link BleManagerCallbacks#onDeviceReady(BluetoothDevice)} callback is called.
*/
private void nextRequest() {
if (mOperationInProgress)
if (operationInProgress)
return;
// Get the first request from the init queue
Request request = mInitQueue != null ? mInitQueue.poll() : null;
Request request = initQueue != null ? initQueue.poll() : null;
// Are we done with initializing?
if (request == null) {
if (mInitInProgress) {
mInitQueue = null; // release the queue
mInitInProgress = false;
mCallbacks.onDeviceReady(mBluetoothDevice);
if (initInProgress) {
initQueue = null; // release the queue
initInProgress = false;
callbacks.onDeviceReady(bluetoothDevice);
}
// If so, we can continue with the task queue
request = mTaskQueue.poll();
request = taskQueue.poll();
if (request == null) {
// Nothing to be done for now
return;
}
}
mOperationInProgress = true;
operationInProgress = true;
boolean result = false;
switch (request.type) {
case CREATE_BOND: {
@@ -994,15 +996,15 @@ public class BleManager implements BleProfileApi {
}
case REQUEST_CONNECTION_PRIORITY: {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mConnectionPriorityOperationInProgress = true;
connectionPriorityOperationInProgress = true;
result = internalRequestConnectionPriority(request.value);
} else {
result = internalRequestConnectionPriority(request.value);
// There is no callback for requestConnectionPriority(...) before Android Oreo.\
// Let's give it some time to finish as the request is an asynchronous operation.
if (result) {
mHandler.postDelayed(() -> {
mOperationInProgress = false;
handler.postDelayed(() -> {
operationInProgress = false;
nextRequest();
}, 100);
}
@@ -1013,8 +1015,8 @@ public class BleManager implements BleProfileApi {
// The result may be false if given characteristic or descriptor were not found on the device.
// In that case, proceed with next operation and ignore the one that failed.
if (!result) {
mConnectionPriorityOperationInProgress = false;
mOperationInProgress = false;
connectionPriorityOperationInProgress = false;
operationInProgress = false;
nextRequest();
}
}

View File

@@ -32,19 +32,19 @@ import android.os.Build;
import java.util.Deque;
public abstract class BleProfile {
private Context mContext;
private BleProfileApi mApi;
private Context context;
private BleProfileApi api;
/* package */ void setApi(final BleProfileApi api) {
this.mContext = api.getContext();
this.mApi = api;
this.context = api.getContext();
this.api = api;
}
/**
* Returns the BLE API for sending data to the remote device.
*/
public BleProfileApi getApi() {
return mApi;
return api;
}
/**
@@ -52,7 +52,7 @@ public abstract class BleProfile {
* @return the context
*/
public Context getContext() {
return mContext;
return context;
}
/**

View File

@@ -62,15 +62,15 @@ public class BleProfileService extends Service implements BleManagerCallbacks {
public static final int STATE_CONNECTING = 2;
public static final int STATE_DISCONNECTING = 3;
private BleManager mBleManager;
private Handler mHandler;
private BleManager bleManager;
private Handler handler;
protected boolean mBound;
private boolean mConnected;
private BluetoothDevice mBluetoothDevice;
private String mDeviceName;
protected boolean bound;
private boolean connected;
private BluetoothDevice bluetoothDevice;
private String deviceName;
private final BroadcastReceiver mBluetoothStateBroadcastReceiver = new BroadcastReceiver() {
private final BroadcastReceiver bluetoothStateBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF);
@@ -92,13 +92,13 @@ public class BleProfileService extends Service implements BleManagerCallbacks {
* Disconnects from the sensor.
*/
public void disconnect() {
if (!mConnected) {
mBleManager.close();
onDeviceDisconnected(mBluetoothDevice);
if (!connected) {
bleManager.close();
onDeviceDisconnected(bluetoothDevice);
return;
}
mBleManager.disconnect();
bleManager.disconnect();
}
/**
@@ -107,7 +107,7 @@ public class BleProfileService extends Service implements BleManagerCallbacks {
* @return device address
*/
public final String getDeviceAddress() {
return mBluetoothDevice.getAddress();
return bluetoothDevice.getAddress();
}
/**
@@ -116,7 +116,7 @@ public class BleProfileService extends Service implements BleManagerCallbacks {
* @return the device name
*/
public final String getDeviceName() {
return mDeviceName;
return deviceName;
}
/**
@@ -125,7 +125,7 @@ public class BleProfileService extends Service implements BleManagerCallbacks {
* @return the Bluetooth device
*/
public final BluetoothDevice getBluetoothDevice() {
return mBluetoothDevice;
return bluetoothDevice;
}
/**
@@ -134,14 +134,14 @@ public class BleProfileService extends Service implements BleManagerCallbacks {
* @return <code>true</code> if device is connected to the sensor, <code>false</code> otherwise
*/
public final boolean isConnected() {
return mConnected;
return connected;
}
/**
* Returns the Profile API. Profile may be null if service discovery has not been performed or the device does not match any profile.
*/
public final BleProfile getProfile() {
return mBleManager.getProfile();
return bleManager.getProfile();
}
}
@@ -157,18 +157,18 @@ public class BleProfileService extends Service implements BleManagerCallbacks {
@Override
public IBinder onBind(final Intent intent) {
mBound = true;
bound = true;
return getBinder();
}
@Override
public final void onRebind(final Intent intent) {
mBound = true;
bound = true;
}
@Override
public final boolean onUnbind(final Intent intent) {
mBound = false;
bound = false;
// We want the onRebind method be called if anything else binds to it again
return true;
@@ -179,13 +179,13 @@ public class BleProfileService extends Service implements BleManagerCallbacks {
public void onCreate() {
super.onCreate();
mHandler = new Handler();
handler = new Handler();
// initialize the manager
mBleManager = new BleManager(this, this);
bleManager = new BleManager(this, this);
// Register broadcast receivers
registerReceiver(mBluetoothStateBroadcastReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
registerReceiver(bluetoothStateBroadcastReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
// Service has now been created
onServiceCreated();
@@ -209,15 +209,15 @@ public class BleProfileService extends Service implements BleManagerCallbacks {
if (intent == null || !intent.hasExtra(EXTRA_DEVICE_ADDRESS))
throw new UnsupportedOperationException("No device address at EXTRA_DEVICE_ADDRESS key");
mDeviceName = intent.getStringExtra(EXTRA_DEVICE_NAME);
deviceName = intent.getStringExtra(EXTRA_DEVICE_NAME);
final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
final BluetoothAdapter adapter = bluetoothManager.getAdapter();
final String deviceAddress = intent.getStringExtra(EXTRA_DEVICE_ADDRESS);
mBluetoothDevice = adapter.getRemoteDevice(deviceAddress);
bluetoothDevice = adapter.getRemoteDevice(deviceAddress);
onServiceStarted();
mBleManager.connect(mBluetoothDevice);
bleManager.connect(bluetoothDevice);
return START_REDELIVER_INTENT;
}
@@ -232,14 +232,14 @@ public class BleProfileService extends Service implements BleManagerCallbacks {
public void onDestroy() {
super.onDestroy();
// Unregister broadcast receivers
unregisterReceiver(mBluetoothStateBroadcastReceiver);
unregisterReceiver(bluetoothStateBroadcastReceiver);
// shutdown the manager
mBleManager.close();
mBleManager = null;
mBluetoothDevice = null;
mDeviceName = null;
mConnected = false;
bleManager.close();
bleManager = null;
bluetoothDevice = null;
deviceName = null;
connected = false;
}
/**
@@ -261,25 +261,25 @@ public class BleProfileService extends Service implements BleManagerCallbacks {
@Override
public boolean shouldEnableBatteryLevelNotifications(final BluetoothDevice device) {
// By default the Battery Level notifications will be enabled only the activity is bound.
return mBound;
return bound;
}
@Override
public void onDeviceConnecting(final BluetoothDevice device) {
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
broadcast.putExtra(EXTRA_DEVICE, bluetoothDevice);
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_CONNECTING);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
}
@Override
public void onDeviceConnected(final BluetoothDevice device) {
mConnected = true;
connected = true;
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_CONNECTED);
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
broadcast.putExtra(EXTRA_DEVICE_NAME, mDeviceName);
broadcast.putExtra(EXTRA_DEVICE, bluetoothDevice);
broadcast.putExtra(EXTRA_DEVICE_NAME, deviceName);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
}
@@ -287,14 +287,14 @@ public class BleProfileService extends Service implements BleManagerCallbacks {
public void onDeviceDisconnecting(final BluetoothDevice device) {
// Notify user about changing the state to DISCONNECTING
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
broadcast.putExtra(EXTRA_DEVICE, bluetoothDevice);
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_DISCONNECTING);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
}
@Override
public void onDeviceDisconnected(final BluetoothDevice device) {
mConnected = false;
connected = false;
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_DISCONNECTED);
@@ -305,10 +305,10 @@ public class BleProfileService extends Service implements BleManagerCallbacks {
@Override
public void onLinklossOccurred(final BluetoothDevice device) {
mConnected = false;
connected = false;
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
broadcast.putExtra(EXTRA_DEVICE, bluetoothDevice);
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_LINK_LOSS);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
}
@@ -316,14 +316,14 @@ public class BleProfileService extends Service implements BleManagerCallbacks {
@Override
public void onDeviceReady(final BluetoothDevice device) {
final Intent broadcast = new Intent(BROADCAST_DEVICE_READY);
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
broadcast.putExtra(EXTRA_DEVICE, bluetoothDevice);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
}
@Override
public void onDeviceNotSupported(final BluetoothDevice device) {
final Intent broadcast = new Intent(BROADCAST_DEVICE_NOT_SUPPORTED);
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
broadcast.putExtra(EXTRA_DEVICE, bluetoothDevice);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
// no need for disconnecting, it will be disconnected by the manager automatically
@@ -334,7 +334,7 @@ public class BleProfileService extends Service implements BleManagerCallbacks {
showToast(no.nordicsemi.android.nrftoolbox.common.R.string.bonding);
final Intent broadcast = new Intent(BROADCAST_BOND_STATE);
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
broadcast.putExtra(EXTRA_DEVICE, bluetoothDevice);
broadcast.putExtra(EXTRA_BOND_STATE, BluetoothDevice.BOND_BONDING);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
}
@@ -344,7 +344,7 @@ public class BleProfileService extends Service implements BleManagerCallbacks {
showToast(no.nordicsemi.android.nrftoolbox.common.R.string.bonded);
final Intent broadcast = new Intent(BROADCAST_BOND_STATE);
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
broadcast.putExtra(EXTRA_DEVICE, bluetoothDevice);
broadcast.putExtra(EXTRA_BOND_STATE, BluetoothDevice.BOND_BONDED);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
}
@@ -352,14 +352,14 @@ public class BleProfileService extends Service implements BleManagerCallbacks {
@Override
public void onError(final BluetoothDevice device, final String message, final int errorCode) {
final Intent broadcast = new Intent(BROADCAST_ERROR);
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
broadcast.putExtra(EXTRA_DEVICE, bluetoothDevice);
broadcast.putExtra(EXTRA_ERROR_MESSAGE, message);
broadcast.putExtra(EXTRA_ERROR_CODE, errorCode);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
// After receiving an error the device will be automatically disconnected.
// Replace it with other implementation if necessary.
mBleManager.disconnect();
bleManager.disconnect();
stopSelf();
}
@@ -370,7 +370,7 @@ public class BleProfileService extends Service implements BleManagerCallbacks {
* an resource id of the message to be shown
*/
private void showToast(final int messageResId) {
mHandler.post(() -> Toast.makeText(BleProfileService.this, messageResId, Toast.LENGTH_SHORT).show());
handler.post(() -> Toast.makeText(BleProfileService.this, messageResId, Toast.LENGTH_SHORT).show());
}
/**

View File

@@ -65,12 +65,12 @@ public class UARTCommandsActivity extends Activity implements UARTCommandsAdapte
public static final String CONFIGURATION = "configuration";
private GoogleApiClient mGoogleApiClient;
private UARTCommandsAdapter mAdapter;
private UARTProfile mProfile;
private long mConfigurationId;
private GoogleApiClient googleApiClient;
private UARTCommandsAdapter adapter;
private UARTProfile profile;
private long configurationId;
private BroadcastReceiver mServiceBroadcastReceiver = new BroadcastReceiver() {
private BroadcastReceiver serviceBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
final String action = intent.getAction();
@@ -100,16 +100,16 @@ public class UARTCommandsActivity extends Activity implements UARTCommandsAdapte
}
};
private ServiceConnection mServiceConnection = new ServiceConnection() {
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(final ComponentName name, final IBinder service) {
final BleProfileService.LocalBinder binder = (BleProfileService.LocalBinder) service;
mProfile = (UARTProfile) binder.getProfile();
profile = (UARTProfile) binder.getProfile();
}
@Override
public void onServiceDisconnected(final ComponentName name) {
mProfile = null;
profile = null;
}
};
@@ -120,22 +120,22 @@ public class UARTCommandsActivity extends Activity implements UARTCommandsAdapte
final Intent intent = getIntent();
final UartConfiguration configuration = intent.getParcelableExtra(CONFIGURATION);
mConfigurationId = configuration.getId();
configurationId = configuration.getId();
// Check if the WEAR device is connected to the UART device itself, or by the phone.
// Binding will fail if we are using phone as proxy as the service has not been started before.
final Intent service = new Intent(this, BleProfileService.class);
bindService(service, mServiceConnection, 0);
bindService(service, serviceConnection, 0);
// Set up tht grid
final GridViewPager pager = findViewById(R.id.pager);
pager.setAdapter(mAdapter = new UARTCommandsAdapter(configuration, this));
pager.setAdapter(adapter = new UARTCommandsAdapter(configuration, this));
final DotsPageIndicator dotsPageIndicator = findViewById(R.id.page_indicator);
dotsPageIndicator.setPager(pager);
// Configure Google API client
mGoogleApiClient = new GoogleApiClient.Builder(this)
googleApiClient = new GoogleApiClient.Builder(this)
.addApi(Wearable.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
@@ -146,39 +146,39 @@ public class UARTCommandsActivity extends Activity implements UARTCommandsAdapte
filter.addAction(BleProfileService.BROADCAST_CONNECTION_STATE);
filter.addAction(BleProfileService.BROADCAST_ERROR);
filter.addAction(UARTProfile.BROADCAST_DATA_RECEIVED);
LocalBroadcastManager.getInstance(this).registerReceiver(mServiceBroadcastReceiver, filter);
LocalBroadcastManager.getInstance(this).registerReceiver(serviceBroadcastReceiver, filter);
}
@Override
protected void onDestroy() {
super.onDestroy();
mGoogleApiClient.unregisterConnectionCallbacks(this);
mGoogleApiClient.unregisterConnectionFailedListener(this);
mGoogleApiClient = null;
googleApiClient.unregisterConnectionCallbacks(this);
googleApiClient.unregisterConnectionFailedListener(this);
googleApiClient = null;
// unbind if we were bound to the service.
unbindService(mServiceConnection);
LocalBroadcastManager.getInstance(this).unregisterReceiver(mServiceBroadcastReceiver);
unbindService(serviceConnection);
LocalBroadcastManager.getInstance(this).unregisterReceiver(serviceBroadcastReceiver);
}
@Override
protected void onStart() {
super.onStart();
mGoogleApiClient.connect();
googleApiClient.connect();
}
@Override
protected void onStop() {
super.onStop();
Wearable.MessageApi.removeListener(mGoogleApiClient, this);
Wearable.DataApi.removeListener(mGoogleApiClient, this);
mGoogleApiClient.disconnect();
Wearable.MessageApi.removeListener(googleApiClient, this);
Wearable.DataApi.removeListener(googleApiClient, this);
googleApiClient.disconnect();
}
@Override
public void onConnected(final Bundle bundle) {
Wearable.DataApi.addListener(mGoogleApiClient, this);
Wearable.MessageApi.addListener(mGoogleApiClient, this);
Wearable.DataApi.addListener(googleApiClient, this);
Wearable.MessageApi.addListener(googleApiClient, this);
}
@Override
@@ -198,7 +198,7 @@ public class UARTCommandsActivity extends Activity implements UARTCommandsAdapte
final long id = ContentUris.parseId(item.getUri());
// Update the configuration only if ID matches
if (id != mConfigurationId)
if (id != configurationId)
continue;
// Configuration added or edited
@@ -207,12 +207,12 @@ public class UARTCommandsActivity extends Activity implements UARTCommandsAdapte
final UartConfiguration configuration = new UartConfiguration(dataMap, id);
// Update UI on UI thread
runOnUiThread(() -> mAdapter.setConfiguration(configuration));
runOnUiThread(() -> adapter.setConfiguration(configuration));
} else if (event.getType() == DataEvent.TYPE_DELETED) {
// Configuration removed
// Update UI on UI thread
runOnUiThread(() -> mAdapter.setConfiguration(null));
runOnUiThread(() -> adapter.setConfiguration(null));
}
}
}
@@ -220,7 +220,7 @@ public class UARTCommandsActivity extends Activity implements UARTCommandsAdapte
@Override
public void onMessageReceived(final MessageEvent messageEvent) {
// If the activity is bound to service it means that it has connected directly to the device. We ignore messages from the handheld.
if (mProfile != null)
if (profile != null)
return;
switch (messageEvent.getPath()) {
@@ -246,8 +246,8 @@ public class UARTCommandsActivity extends Activity implements UARTCommandsAdapte
break;
}
if (mProfile != null)
mProfile.send(text);
if (profile != null)
profile.send(text);
else
sendMessageToHandheld(this, text);
}

View File

@@ -34,21 +34,21 @@ import no.nordicsemi.android.nrftoolbox.uart.domain.Command;
import no.nordicsemi.android.nrftoolbox.uart.domain.UartConfiguration;
public class UARTCommandsAdapter extends GridPagerAdapter {
private final OnCommandSelectedListener mListener;
private UartConfiguration mConfiguration;
private final OnCommandSelectedListener listener;
private UartConfiguration configuration;
public interface OnCommandSelectedListener {
void onCommandSelected(final Command command);
}
public UARTCommandsAdapter(final UartConfiguration configuration, final OnCommandSelectedListener listener) {
this.mConfiguration = configuration;
this.mListener = listener;
this.configuration = configuration;
this.listener = listener;
}
public void setConfiguration(final UartConfiguration configuration) {
// Configuration is null when it has been deleted on the handheld
this.mConfiguration = configuration;
this.configuration = configuration;
notifyDataSetChanged();
}
@@ -59,7 +59,7 @@ public class UARTCommandsAdapter extends GridPagerAdapter {
@Override
public int getColumnCount(final int row) {
final int count = mConfiguration != null ? mConfiguration.getCommands().length : 0;
final int count = configuration != null ? configuration.getCommands().length : 0;
return count > 0 ? count : 1; // Empty view
}
@@ -68,13 +68,13 @@ public class UARTCommandsAdapter extends GridPagerAdapter {
final View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.action_item, viewGroup, false);
viewGroup.addView(view);
final Command[] commands = mConfiguration != null ? mConfiguration.getCommands() : null;
final Command[] commands = configuration != null ? configuration.getCommands() : null;
if (commands != null && commands.length > 0) {
final Command command = commands[column];
final CircularButton icon = view.findViewById(R.id.icon);
icon.getImageDrawable().setLevel(command.getIconIndex());
icon.setOnClickListener(v -> mListener.onCommandSelected(command));
icon.setOnClickListener(v -> listener.onCommandSelected(command));
} else {
// Hide the icon
view.findViewById(R.id.icon).setVisibility(View.GONE);

View File

@@ -43,19 +43,19 @@ public class UARTConfigurationItemLayout extends LinearLayout implements Wearabl
private static final float SHRINK_LABEL_ALPHA = .5f;
private static final float EXPAND_LABEL_ALPHA = 1f;
private float mExpandCircleRadius;
private float mShrinkCircleRadius;
private float expandCircleRadius;
private float shrinkCircleRadius;
private ObjectAnimator mExpandCircleAnimator;
private ObjectAnimator mFadeInLabelAnimator;
private AnimatorSet mExpandAnimator;
private ObjectAnimator expandCircleAnimator;
private ObjectAnimator fadeInLabelAnimator;
private AnimatorSet expandAnimator;
private ObjectAnimator mShrinkCircleAnimator;
private ObjectAnimator mFadeOutLabelAnimator;
private AnimatorSet mShrinkAnimator;
private ObjectAnimator shrinkCircleAnimator;
private ObjectAnimator fadeOutLabelAnimator;
private AnimatorSet shrinkAnimator;
private TextView mName;
private CircledImageView mIcon;
private TextView name;
private CircledImageView icon;
public UARTConfigurationItemLayout(final Context context) {
this(context, null, 0);
@@ -73,53 +73,53 @@ public class UARTConfigurationItemLayout extends LinearLayout implements Wearabl
protected void onFinishInflate() {
super.onFinishInflate();
mName = findViewById(R.id.name);
mIcon = findViewById(R.id.icon);
mExpandCircleRadius = mIcon.getCircleRadius();
mShrinkCircleRadius = mExpandCircleRadius * SHRINK_CIRCLE_RATIO;
name = findViewById(R.id.name);
icon = findViewById(R.id.icon);
expandCircleRadius = icon.getCircleRadius();
shrinkCircleRadius = expandCircleRadius * SHRINK_CIRCLE_RATIO;
mShrinkCircleAnimator = ObjectAnimator.ofFloat(mIcon, "circleRadius", mExpandCircleRadius, mShrinkCircleRadius);
mFadeOutLabelAnimator = ObjectAnimator.ofFloat(mName, "alpha", EXPAND_LABEL_ALPHA, SHRINK_LABEL_ALPHA);
mShrinkAnimator = new AnimatorSet().setDuration(ANIMATION_DURATION_MS);
mShrinkAnimator.playTogether(mShrinkCircleAnimator, mFadeOutLabelAnimator);
shrinkCircleAnimator = ObjectAnimator.ofFloat(icon, "circleRadius", expandCircleRadius, shrinkCircleRadius);
fadeOutLabelAnimator = ObjectAnimator.ofFloat(name, "alpha", EXPAND_LABEL_ALPHA, SHRINK_LABEL_ALPHA);
shrinkAnimator = new AnimatorSet().setDuration(ANIMATION_DURATION_MS);
shrinkAnimator.playTogether(shrinkCircleAnimator, fadeOutLabelAnimator);
mExpandCircleAnimator = ObjectAnimator.ofFloat(mIcon, "circleRadius", mShrinkCircleRadius, mExpandCircleRadius);
mFadeInLabelAnimator = ObjectAnimator.ofFloat(mName, "alpha", SHRINK_LABEL_ALPHA, EXPAND_LABEL_ALPHA);
mExpandAnimator = new AnimatorSet().setDuration(ANIMATION_DURATION_MS);
mExpandAnimator.playTogether(mExpandCircleAnimator, mFadeInLabelAnimator);
expandCircleAnimator = ObjectAnimator.ofFloat(icon, "circleRadius", shrinkCircleRadius, expandCircleRadius);
fadeInLabelAnimator = ObjectAnimator.ofFloat(name, "alpha", SHRINK_LABEL_ALPHA, EXPAND_LABEL_ALPHA);
expandAnimator = new AnimatorSet().setDuration(ANIMATION_DURATION_MS);
expandAnimator.playTogether(expandCircleAnimator, fadeInLabelAnimator);
}
@Override
public void onCenterPosition(final boolean animate) {
if (animate) {
mShrinkAnimator.cancel();
if (!mExpandAnimator.isRunning()) {
mExpandCircleAnimator.setFloatValues(mIcon.getCircleRadius(), mExpandCircleRadius);
mFadeInLabelAnimator.setFloatValues(mName.getAlpha(), EXPAND_LABEL_ALPHA);
mExpandAnimator.start();
shrinkAnimator.cancel();
if (!expandAnimator.isRunning()) {
expandCircleAnimator.setFloatValues(icon.getCircleRadius(), expandCircleRadius);
fadeInLabelAnimator.setFloatValues(name.getAlpha(), EXPAND_LABEL_ALPHA);
expandAnimator.start();
}
} else {
mExpandAnimator.cancel();
mIcon.setCircleRadius(mExpandCircleRadius);
mName.setAlpha(EXPAND_LABEL_ALPHA);
expandAnimator.cancel();
icon.setCircleRadius(expandCircleRadius);
name.setAlpha(EXPAND_LABEL_ALPHA);
}
mIcon.setEnabled(true);
icon.setEnabled(true);
}
@Override
public void onNonCenterPosition(final boolean animate) {
if (animate) {
mExpandAnimator.cancel();
if (!mShrinkAnimator.isRunning()) {
mShrinkCircleAnimator.setFloatValues(mIcon.getCircleRadius(), mShrinkCircleRadius);
mFadeOutLabelAnimator.setFloatValues(mName.getAlpha(), SHRINK_LABEL_ALPHA);
mShrinkAnimator.start();
expandAnimator.cancel();
if (!shrinkAnimator.isRunning()) {
shrinkCircleAnimator.setFloatValues(icon.getCircleRadius(), shrinkCircleRadius);
fadeOutLabelAnimator.setFloatValues(name.getAlpha(), SHRINK_LABEL_ALPHA);
shrinkAnimator.start();
}
} else {
mShrinkAnimator.cancel();
mIcon.setCircleRadius(mShrinkCircleRadius);
mName.setAlpha(SHRINK_LABEL_ALPHA);
shrinkAnimator.cancel();
icon.setCircleRadius(shrinkCircleRadius);
name.setAlpha(SHRINK_LABEL_ALPHA);
}
mIcon.setEnabled(false);
icon.setEnabled(false);
}
}

View File

@@ -60,11 +60,11 @@ import no.nordicsemi.android.nrftoolbox.uart.domain.UartConfiguration;
public class UARTConfigurationsActivity extends Activity implements GoogleApiClient.ConnectionCallbacks,
DataApi.DataListener, GoogleApiClient.OnConnectionFailedListener, WearableListView.ClickListener, MessageApi.MessageListener {
private UARTConfigurationsAdapter mAdapter;
private GoogleApiClient mGoogleApiClient;
private BleProfileService.LocalBinder mBinder;
private UARTConfigurationsAdapter adapter;
private GoogleApiClient googleApiClient;
private BleProfileService.LocalBinder binder;
private BroadcastReceiver mServiceBroadcastReceiver = new BroadcastReceiver() {
private BroadcastReceiver serviceBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
final String action = intent.getAction();
@@ -87,15 +87,15 @@ public class UARTConfigurationsActivity extends Activity implements GoogleApiCli
}
};
private ServiceConnection mServiceConnection = new ServiceConnection() {
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(final ComponentName name, final IBinder service) {
mBinder = (BleProfileService.LocalBinder) service;
binder = (BleProfileService.LocalBinder) service;
}
@Override
public void onServiceDisconnected(final ComponentName name) {
mBinder = null;
binder = null;
}
};
@@ -107,13 +107,13 @@ public class UARTConfigurationsActivity extends Activity implements GoogleApiCli
// Check if the WEAR device is connected to the UART device itself, or by the phone.
// Binding will fail if we are using phone as proxy as the service has not been started before.
final Intent service = new Intent(this, BleProfileService.class);
bindService(service, mServiceConnection, 0);
bindService(service, serviceConnection, 0);
final WearableListView listView = findViewById(R.id.list);
listView.setClickListener(this);
listView.setAdapter(mAdapter = new UARTConfigurationsAdapter(this));
listView.setAdapter(adapter = new UARTConfigurationsAdapter(this));
mGoogleApiClient = new GoogleApiClient.Builder(this)
googleApiClient = new GoogleApiClient.Builder(this)
.addApi(Wearable.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
@@ -124,48 +124,48 @@ public class UARTConfigurationsActivity extends Activity implements GoogleApiCli
final IntentFilter filter = new IntentFilter();
filter.addAction(BleProfileService.BROADCAST_CONNECTION_STATE);
filter.addAction(BleProfileService.BROADCAST_ERROR);
LocalBroadcastManager.getInstance(this).registerReceiver(mServiceBroadcastReceiver, filter);
LocalBroadcastManager.getInstance(this).registerReceiver(serviceBroadcastReceiver, filter);
}
@Override
protected void onDestroy() {
super.onDestroy();
mGoogleApiClient.unregisterConnectionCallbacks(this);
mGoogleApiClient.unregisterConnectionFailedListener(this);
mGoogleApiClient = null;
googleApiClient.unregisterConnectionCallbacks(this);
googleApiClient.unregisterConnectionFailedListener(this);
googleApiClient = null;
// If we were bound to the service, disconnect and unbind. The service will terminate itself when disconnected.
if (mBinder != null) {
mBinder.disconnect();
if (binder != null) {
binder.disconnect();
}
unbindService(mServiceConnection);
LocalBroadcastManager.getInstance(this).unregisterReceiver(mServiceBroadcastReceiver);
unbindService(serviceConnection);
LocalBroadcastManager.getInstance(this).unregisterReceiver(serviceBroadcastReceiver);
}
@Override
protected void onStart() {
super.onStart();
mGoogleApiClient.connect();
googleApiClient.connect();
}
@Override
protected void onStop() {
super.onStop();
Wearable.MessageApi.removeListener(mGoogleApiClient, this);
Wearable.DataApi.removeListener(mGoogleApiClient, this);
mGoogleApiClient.disconnect();
Wearable.MessageApi.removeListener(googleApiClient, this);
Wearable.DataApi.removeListener(googleApiClient, this);
googleApiClient.disconnect();
}
@Override
public void onConnected(final Bundle bundle) {
Wearable.DataApi.addListener(mGoogleApiClient, this);
Wearable.MessageApi.addListener(mGoogleApiClient, this);
Wearable.DataApi.addListener(googleApiClient, this);
Wearable.MessageApi.addListener(googleApiClient, this);
populateConfigurations();
}
@Override
public void onConnectionSuspended(final int cause) {
Wearable.DataApi.removeListener(mGoogleApiClient, this);
Wearable.DataApi.removeListener(googleApiClient, this);
finish();
}
@@ -182,7 +182,7 @@ public class UARTConfigurationsActivity extends Activity implements GoogleApiCli
@Override
public void onMessageReceived(final MessageEvent messageEvent) {
// If the activity is bound to service it means that it has connected directly to the device. We ignore messages from the handheld.
if (mBinder != null)
if (binder != null)
return;
switch (messageEvent.getPath()) {
@@ -215,8 +215,8 @@ public class UARTConfigurationsActivity extends Activity implements GoogleApiCli
* This method read the UART configurations from the DataApi and populates the adapter with them.
*/
private void populateConfigurations() {
if (mGoogleApiClient.isConnected()) {
final PendingResult<DataItemBuffer> results = Wearable.DataApi.getDataItems(mGoogleApiClient, Uri.parse("wear:" + Constants.UART.CONFIGURATIONS), DataApi.FILTER_PREFIX);
if (googleApiClient.isConnected()) {
final PendingResult<DataItemBuffer> results = Wearable.DataApi.getDataItems(googleApiClient, Uri.parse("wear:" + Constants.UART.CONFIGURATIONS), DataApi.FILTER_PREFIX);
results.setResultCallback(dataItems -> {
final List<UartConfiguration> configurations = new ArrayList<>(dataItems.getCount());
for (int i = 0; i < dataItems.getCount(); ++i) {
@@ -226,7 +226,7 @@ public class UARTConfigurationsActivity extends Activity implements GoogleApiCli
final UartConfiguration configuration = new UartConfiguration(dataMap, id);
configurations.add(configuration);
}
mAdapter.setConfigurations(configurations);
adapter.setConfigurations(configurations);
dataItems.release();
});
}

View File

@@ -31,58 +31,60 @@ import android.widget.TextView;
import java.util.List;
import androidx.annotation.NonNull;
import no.nordicsemi.android.nrftoolbox.R;
import no.nordicsemi.android.nrftoolbox.uart.domain.UartConfiguration;
public class UARTConfigurationsAdapter extends WearableListView.Adapter {
private final LayoutInflater mInflater;
private List<UartConfiguration> mConfigurations;
private final LayoutInflater inflater;
private List<UartConfiguration> configurations;
public UARTConfigurationsAdapter(final Context context) {
mInflater = LayoutInflater.from(context);
inflater = LayoutInflater.from(context);
}
/**
* Populates the adapter with list of configurations.
*/
public void setConfigurations(final List<UartConfiguration> configurations) {
mConfigurations = configurations;
this.configurations = configurations;
notifyDataSetChanged();
}
@NonNull
@Override
public WearableListView.ViewHolder onCreateViewHolder(final ViewGroup viewGroup, final int viewType) {
return new ConfigurationViewHolder(mInflater.inflate(R.layout.configuration_item, viewGroup, false));
public WearableListView.ViewHolder onCreateViewHolder(@NonNull final ViewGroup viewGroup, final int viewType) {
return new ConfigurationViewHolder(inflater.inflate(R.layout.configuration_item, viewGroup, false));
}
@Override
public void onBindViewHolder(final WearableListView.ViewHolder holder, final int position) {
public void onBindViewHolder(@NonNull final WearableListView.ViewHolder holder, final int position) {
final ConfigurationViewHolder viewHolder = (ConfigurationViewHolder) holder;
viewHolder.setConfiguration(mConfigurations.get(position));
viewHolder.setConfiguration(configurations.get(position));
}
@Override
public int getItemCount() {
return mConfigurations != null ? mConfigurations.size() : 0;
return configurations != null ? configurations.size() : 0;
}
public static class ConfigurationViewHolder extends WearableListView.ViewHolder {
private UartConfiguration mConfiguration;
private TextView mName;
private UartConfiguration configuration;
private TextView name;
public ConfigurationViewHolder(final View itemView) {
super(itemView);
mName = itemView.findViewById(R.id.name);
name = itemView.findViewById(R.id.name);
}
private void setConfiguration(final UartConfiguration configuration) {
mConfiguration = configuration;
mName.setText(configuration.getName());
this.configuration = configuration;
name.setText(configuration.getName());
}
public UartConfiguration getConfiguration() {
return mConfiguration;
return configuration;
}
}
}

View File

@@ -59,36 +59,36 @@ public class UARTProfile extends BleProfile {
return service != null && service.getCharacteristic(UART_TX_CHARACTERISTIC_UUID) != null && service.getCharacteristic(UART_RX_CHARACTERISTIC_UUID) != null;
}
private BluetoothGattCharacteristic mTXCharacteristic;
private BluetoothGattCharacteristic mRXCharacteristic;
private byte[] mOutgoingBuffer;
private int mBufferOffset;
private BluetoothGattCharacteristic tXCharacteristic;
private BluetoothGattCharacteristic rXCharacteristic;
private byte[] outgoingBuffer;
private int bufferOffset;
@Override
protected Deque<BleManager.Request> initGatt(final BluetoothGatt gatt) {
final BluetoothGattService service = gatt.getService(UART_SERVICE_UUID);
mTXCharacteristic = service.getCharacteristic(UART_TX_CHARACTERISTIC_UUID);
mRXCharacteristic = service.getCharacteristic(UART_RX_CHARACTERISTIC_UUID);
tXCharacteristic = service.getCharacteristic(UART_TX_CHARACTERISTIC_UUID);
rXCharacteristic = service.getCharacteristic(UART_RX_CHARACTERISTIC_UUID);
final int rxProperties = mRXCharacteristic.getProperties();
final int rxProperties = rXCharacteristic.getProperties();
boolean writeRequest = (rxProperties & BluetoothGattCharacteristic.PROPERTY_WRITE) > 0;
// Set the WRITE REQUEST type when the characteristic supports it. This will allow to send long write (also if the characteristic support it).
// In case there is no WRITE REQUEST property, this manager will divide texts longer then 20 bytes into up to 20 bytes chunks.
if (writeRequest)
mRXCharacteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
rXCharacteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
// We don't want to enable notifications on TX characteristic as we are not showing them here. A watch may be just used to send data. At least now.
// final LinkedList<BleProfileApi.Request> requests = new LinkedList<>();
// requests.add(BleProfileApi.Request.newEnableNotificationsRequest(mTXCharacteristic));
// requests.add(BleProfileApi.Request.newEnableNotificationsRequest(tXCharacteristic));
// return requests;
return null;
}
@Override
protected void release() {
mTXCharacteristic = null;
mRXCharacteristic = null;
tXCharacteristic = null;
rXCharacteristic = null;
}
@Override
@@ -102,13 +102,13 @@ public class UARTProfile extends BleProfile {
@Override
protected void onCharacteristicWrite(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
// When the whole buffer has been sent
final byte[] buffer = mOutgoingBuffer;
if (mBufferOffset == buffer.length) {
mOutgoingBuffer = null;
final byte[] buffer = outgoingBuffer;
if (bufferOffset == buffer.length) {
outgoingBuffer = null;
} else { // Otherwise...
final int length = Math.min(buffer.length - mBufferOffset, MAX_PACKET_SIZE);
getApi().enqueue(BleProfileApi.Request.newWriteRequest(mRXCharacteristic, buffer, mBufferOffset, length));
mBufferOffset += length;
final int length = Math.min(buffer.length - bufferOffset, MAX_PACKET_SIZE);
getApi().enqueue(BleProfileApi.Request.newWriteRequest(rXCharacteristic, buffer, bufferOffset, length));
bufferOffset += length;
}
}
@@ -118,25 +118,25 @@ public class UARTProfile extends BleProfile {
*/
public void send(final String text) {
// Are we connected?
if (mRXCharacteristic == null)
if (rXCharacteristic == null)
return;
// An outgoing buffer may not be null if there is already another packet being sent. We do nothing in this case.
if (!TextUtils.isEmpty(text) && mOutgoingBuffer == null) {
final byte[] buffer = mOutgoingBuffer = text.getBytes();
mBufferOffset = 0;
if (!TextUtils.isEmpty(text) && outgoingBuffer == null) {
final byte[] buffer = outgoingBuffer = text.getBytes();
bufferOffset = 0;
// Depending on whether the characteristic has the WRITE REQUEST property or not, we will either send it as it is (hoping the long write is implemented),
// or divide it into up to 20 bytes chunks and send them one by one.
final boolean writeRequest = (mRXCharacteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE) > 0;
final boolean writeRequest = (rXCharacteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE) > 0;
if (!writeRequest) { // no WRITE REQUEST property
final int length = Math.min(buffer.length, MAX_PACKET_SIZE);
mBufferOffset += length;
getApi().enqueue(BleProfileApi.Request.newWriteRequest(mRXCharacteristic, buffer, 0, length));
bufferOffset += length;
getApi().enqueue(BleProfileApi.Request.newWriteRequest(rXCharacteristic, buffer, 0, length));
} else { // there is WRITE REQUEST property, let's try Long Write
mBufferOffset = buffer.length;
getApi().enqueue(BleProfileApi.Request.newWriteRequest(mRXCharacteristic, buffer, 0, buffer.length));
bufferOffset = buffer.length;
getApi().enqueue(BleProfileApi.Request.newWriteRequest(rXCharacteristic, buffer, 0, buffer.length));
}
}
}