mirror of
https://github.com/aljazceru/Android-nRF-Toolbox.git
synced 2025-12-21 00:14:24 +01:00
Migration to BLE Library 2.2.0-alpha05
Getting rid of hungarian notation
This commit is contained in:
@@ -57,7 +57,7 @@ dependencies {
|
|||||||
|
|
||||||
// Import the BLE Common Library.
|
// Import the BLE Common Library.
|
||||||
// The BLE Common Library depends on BLE Library. It is enough to include the first one.
|
// 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,
|
// 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
|
// clone both projects from GitHub and replace the line above with the following
|
||||||
// (and also the according lines in the settings.gradle):
|
// (and also the according lines in the settings.gradle):
|
||||||
|
|||||||
@@ -57,19 +57,23 @@ public class AppHelpFragment extends DialogFragment {
|
|||||||
@Override
|
@Override
|
||||||
@NonNull
|
@NonNull
|
||||||
public Dialog onCreateDialog(final Bundle savedInstanceState) {
|
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 StringBuilder text = new StringBuilder(getString(args.getInt(ARG_TEXT)));
|
||||||
|
|
||||||
final boolean appendVersion = args.getBoolean(ARG_VERSION);
|
final boolean appendVersion = args.getBoolean(ARG_VERSION);
|
||||||
if (appendVersion) {
|
if (appendVersion) {
|
||||||
try {
|
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));
|
text.append(getString(R.string.about_version, version));
|
||||||
} catch (final NameNotFoundException e) {
|
} catch (final NameNotFoundException e) {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new AlertDialog.Builder(getActivity()).setTitle(R.string.about_title).setMessage(text)
|
return new AlertDialog.Builder(requireContext())
|
||||||
.setPositiveButton(R.string.ok, null).create();
|
.setTitle(R.string.about_title)
|
||||||
|
.setMessage(text)
|
||||||
|
.setPositiveButton(R.string.ok, null)
|
||||||
|
.create();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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_CLASS = NRF_CONNECT_PACKAGE + ".DeviceListActivity";
|
||||||
private static final String NRF_CONNECT_MARKET_URI = "market://details?id=no.nordicsemi.android.mcp";
|
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_APP = "application/vnd.no.nordicsemi.type.app";
|
||||||
public static final String EXTRA_ADDRESS = "application/vnd.no.nordicsemi.type.address";
|
public static final String EXTRA_ADDRESS = "application/vnd.no.nordicsemi.type.address";
|
||||||
|
|
||||||
private DrawerLayout mDrawerLayout;
|
private DrawerLayout drawerLayout;
|
||||||
private ActionBarDrawerToggle mDrawerToggle;
|
private ActionBarDrawerToggle drawerToggle;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(final Bundle savedInstanceState) {
|
protected void onCreate(final Bundle savedInstanceState) {
|
||||||
@@ -80,18 +80,18 @@ public class FeaturesActivity extends AppCompatActivity {
|
|||||||
if (!ensureBLEExists())
|
if (!ensureBLEExists())
|
||||||
finish();
|
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);
|
drawer.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
|
||||||
|
|
||||||
// Set the drawer toggle as the DrawerListener
|
// 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
|
@Override
|
||||||
public void onDrawerSlide(final View drawerView, final float slideOffset) {
|
public void onDrawerSlide(final View drawerView, final float slideOffset) {
|
||||||
// Disable the Hamburger icon animation
|
// Disable the Hamburger icon animation
|
||||||
super.onDrawerSlide(drawerView, 0);
|
super.onDrawerSlide(drawerView, 0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
drawer.addDrawerListener(mDrawerToggle);
|
drawer.addDrawerListener(drawerToggle);
|
||||||
|
|
||||||
// setup plug-ins in the drawer
|
// setup plug-ins in the drawer
|
||||||
setupPluginsInDrawer(drawer.findViewById(R.id.plugin_container));
|
setupPluginsInDrawer(drawer.findViewById(R.id.plugin_container));
|
||||||
@@ -130,23 +130,24 @@ public class FeaturesActivity extends AppCompatActivity {
|
|||||||
protected void onPostCreate(final Bundle savedInstanceState) {
|
protected void onPostCreate(final Bundle savedInstanceState) {
|
||||||
super.onPostCreate(savedInstanceState);
|
super.onPostCreate(savedInstanceState);
|
||||||
// Sync the toggle state after onRestoreInstanceState has occurred.
|
// Sync the toggle state after onRestoreInstanceState has occurred.
|
||||||
mDrawerToggle.syncState();
|
drawerToggle.syncState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onConfigurationChanged(@NonNull final Configuration newConfig) {
|
public void onConfigurationChanged(@NonNull final Configuration newConfig) {
|
||||||
super.onConfigurationChanged(newConfig);
|
super.onConfigurationChanged(newConfig);
|
||||||
mDrawerToggle.onConfigurationChanged(newConfig);
|
drawerToggle.onConfigurationChanged(newConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
public boolean onOptionsItemSelected(@NonNull final MenuItem item) {
|
||||||
// Pass the event to ActionBarDrawerToggle, if it returns
|
// Pass the event to ActionBarDrawerToggle, if it returns
|
||||||
// true, then it has handled the app icon touch event
|
// true, then it has handled the app icon touch event
|
||||||
if (mDrawerToggle.onOptionsItemSelected(item)) {
|
if (drawerToggle.onOptionsItemSelected(item)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection SwitchStatementWithTooFewBranches
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
case R.id.action_about:
|
case R.id.action_about:
|
||||||
final AppHelpFragment fragment = AppHelpFragment.getInstance(R.string.about_text, true);
|
final AppHelpFragment fragment = AppHelpFragment.getInstance(R.string.about_text, true);
|
||||||
@@ -185,7 +186,7 @@ public class FeaturesActivity extends AppCompatActivity {
|
|||||||
} catch (final ActivityNotFoundException e) {
|
} catch (final ActivityNotFoundException e) {
|
||||||
Toast.makeText(FeaturesActivity.this, R.string.no_application_play, Toast.LENGTH_SHORT).show();
|
Toast.makeText(FeaturesActivity.this, R.string.no_application_play, Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
mDrawerLayout.closeDrawers();
|
drawerLayout.closeDrawers();
|
||||||
});
|
});
|
||||||
|
|
||||||
// look for other plug-ins
|
// 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_NO_ANIMATION);
|
||||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
mDrawerLayout.closeDrawers();
|
drawerLayout.closeDrawers();
|
||||||
});
|
});
|
||||||
container.addView(item);
|
container.addView(item);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,27 +32,27 @@ public class PermissionRationaleFragment extends DialogFragment {
|
|||||||
private static final String ARG_PERMISSION = "ARG_PERMISSION";
|
private static final String ARG_PERMISSION = "ARG_PERMISSION";
|
||||||
private static final String ARG_TEXT = "ARG_TEXT";
|
private static final String ARG_TEXT = "ARG_TEXT";
|
||||||
|
|
||||||
private PermissionDialogListener mListener;
|
private PermissionDialogListener listener;
|
||||||
|
|
||||||
public interface PermissionDialogListener {
|
public interface PermissionDialogListener {
|
||||||
void onRequestPermission(final String permission);
|
void onRequestPermission(final String permission);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(final Context context) {
|
public void onAttach(@NonNull final Context context) {
|
||||||
super.onAttach(context);
|
super.onAttach(context);
|
||||||
|
|
||||||
if (context instanceof PermissionDialogListener) {
|
if (context instanceof PermissionDialogListener) {
|
||||||
mListener = (PermissionDialogListener) context;
|
listener = (PermissionDialogListener) context;
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("The parent activity must impelemnt PermissionDialogListener");
|
throw new IllegalArgumentException("The parent activity must implement PermissionDialogListener");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDetach() {
|
public void onDetach() {
|
||||||
super.onDetach();
|
super.onDetach();
|
||||||
mListener = null;
|
listener = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PermissionRationaleFragment getInstance(final int aboutResId, final String permission) {
|
public static PermissionRationaleFragment getInstance(final int aboutResId, final String permission) {
|
||||||
@@ -69,10 +69,10 @@ public class PermissionRationaleFragment extends DialogFragment {
|
|||||||
@Override
|
@Override
|
||||||
@NonNull
|
@NonNull
|
||||||
public Dialog onCreateDialog(final Bundle savedInstanceState) {
|
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 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)
|
.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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,27 +37,29 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import no.nordicsemi.android.nrftoolbox.R;
|
import no.nordicsemi.android.nrftoolbox.R;
|
||||||
|
|
||||||
public class AppAdapter extends BaseAdapter {
|
public class AppAdapter extends BaseAdapter {
|
||||||
private static final String CATEGORY = "no.nordicsemi.android.nrftoolbox.LAUNCHER";
|
private static final String CATEGORY = "no.nordicsemi.android.nrftoolbox.LAUNCHER";
|
||||||
private static final String NRF_CONNECT_PACKAGE = "no.nordicsemi.android.mcp";
|
private static final String NRF_CONNECT_PACKAGE = "no.nordicsemi.android.mcp";
|
||||||
|
|
||||||
private final Context mContext;
|
private final Context context;
|
||||||
private final PackageManager mPackageManager;
|
private final PackageManager packageManager;
|
||||||
private final LayoutInflater mInflater;
|
private final LayoutInflater inflater;
|
||||||
private final List<ResolveInfo> mApplications;
|
private final List<ResolveInfo> applications;
|
||||||
|
|
||||||
public AppAdapter(final Context context) {
|
public AppAdapter(@NonNull final Context context) {
|
||||||
mContext = context;
|
this.context = context;
|
||||||
mInflater = LayoutInflater.from(context);
|
this.inflater = LayoutInflater.from(context);
|
||||||
|
|
||||||
// get nRF installed app plugins from package manager
|
// 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);
|
final Intent intent = new Intent(Intent.ACTION_MAIN);
|
||||||
intent.addCategory(CATEGORY);
|
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.
|
// 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) {
|
for (final ResolveInfo info : appList) {
|
||||||
if (NRF_CONNECT_PACKAGE.equals(info.activityInfo.packageName)) {
|
if (NRF_CONNECT_PACKAGE.equals(info.activityInfo.packageName)) {
|
||||||
@@ -70,24 +72,24 @@ public class AppAdapter extends BaseAdapter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getCount() {
|
public int getCount() {
|
||||||
return mApplications.size();
|
return applications.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getItem(int position) {
|
public Object getItem(final int position) {
|
||||||
return mApplications.get(position);
|
return applications.get(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getItemId(int position) {
|
public long getItemId(final int position) {
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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;
|
View view = convertView;
|
||||||
if (view == null) {
|
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();
|
final ViewHolder holder = new ViewHolder();
|
||||||
holder.view = view;
|
holder.view = view;
|
||||||
@@ -96,8 +98,8 @@ public class AppAdapter extends BaseAdapter {
|
|||||||
view.setTag(holder);
|
view.setTag(holder);
|
||||||
}
|
}
|
||||||
|
|
||||||
final ResolveInfo info = mApplications.get(position);
|
final ResolveInfo info = applications.get(position);
|
||||||
final PackageManager pm = mPackageManager;
|
final PackageManager pm = packageManager;
|
||||||
|
|
||||||
final ViewHolder holder = (ViewHolder) view.getTag();
|
final ViewHolder holder = (ViewHolder) view.getTag();
|
||||||
holder.icon.setImageDrawable(info.loadIcon(pm));
|
holder.icon.setImageDrawable(info.loadIcon(pm));
|
||||||
@@ -106,7 +108,7 @@ public class AppAdapter extends BaseAdapter {
|
|||||||
final Intent intent = new Intent();
|
final Intent intent = new Intent();
|
||||||
intent.setComponent(new ComponentName(info.activityInfo.packageName, info.activityInfo.name));
|
intent.setComponent(new ComponentName(info.activityInfo.packageName, info.activityInfo.name));
|
||||||
intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
|
intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
|
||||||
mContext.startActivity(intent);
|
context.startActivity(intent);
|
||||||
});
|
});
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package no.nordicsemi.android.nrftoolbox.app;
|
package no.nordicsemi.android.nrftoolbox.app;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@@ -133,13 +134,15 @@ import no.nordicsemi.android.nrftoolbox.R;
|
|||||||
* @see #setListAdapter
|
* @see #setListAdapter
|
||||||
* @see android.widget.ExpandableListView
|
* @see android.widget.ExpandableListView
|
||||||
*/
|
*/
|
||||||
|
@SuppressLint("Registered")
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public class ExpandableListActivity extends AppCompatActivity implements
|
public class ExpandableListActivity extends AppCompatActivity implements
|
||||||
OnCreateContextMenuListener,
|
OnCreateContextMenuListener,
|
||||||
ExpandableListView.OnChildClickListener, ExpandableListView.OnGroupCollapseListener,
|
ExpandableListView.OnChildClickListener, ExpandableListView.OnGroupCollapseListener,
|
||||||
ExpandableListView.OnGroupExpandListener {
|
ExpandableListView.OnGroupExpandListener {
|
||||||
ExpandableListAdapter mAdapter;
|
ExpandableListAdapter adapter;
|
||||||
ExpandableListView mList;
|
ExpandableListView list;
|
||||||
boolean mFinishedStart = false;
|
boolean finishedStart = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override this to populate the context menu when an item is long pressed. menuInfo will contain an
|
* 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
|
@Override
|
||||||
public void onContentChanged() {
|
public void onContentChanged() {
|
||||||
super.onContentChanged();
|
super.onContentChanged();
|
||||||
View emptyView = findViewById(R.id.empty);
|
final View emptyView = findViewById(R.id.empty);
|
||||||
mList = findViewById(R.id.list);
|
list = findViewById(R.id.list);
|
||||||
if (mList == null) {
|
if (list == null) {
|
||||||
throw new RuntimeException(
|
throw new RuntimeException(
|
||||||
"Your content must have a ExpandableListView whose id attribute is " +
|
"Your content must have a ExpandableListView whose id attribute is " +
|
||||||
"'R.id.list'");
|
"'R.id.list'");
|
||||||
}
|
}
|
||||||
if (emptyView != null) {
|
if (emptyView != null) {
|
||||||
mList.setEmptyView(emptyView);
|
list.setEmptyView(emptyView);
|
||||||
}
|
}
|
||||||
mList.setOnChildClickListener(this);
|
list.setOnChildClickListener(this);
|
||||||
mList.setOnGroupExpandListener(this);
|
list.setOnGroupExpandListener(this);
|
||||||
mList.setOnGroupCollapseListener(this);
|
list.setOnGroupCollapseListener(this);
|
||||||
|
|
||||||
if (mFinishedStart) {
|
if (finishedStart) {
|
||||||
setListAdapter(mAdapter);
|
setListAdapter(adapter);
|
||||||
}
|
}
|
||||||
mFinishedStart = true;
|
finishedStart = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provide the adapter for the expandable list.
|
* Provide the adapter for the expandable list.
|
||||||
*/
|
*/
|
||||||
public void setListAdapter(ExpandableListAdapter adapter) {
|
public void setListAdapter(final ExpandableListAdapter adapter) {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
ensureList();
|
ensureList();
|
||||||
mAdapter = adapter;
|
this.adapter = adapter;
|
||||||
mList.setAdapter(adapter);
|
list.setAdapter(adapter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,18 +237,18 @@ public class ExpandableListActivity extends AppCompatActivity implements
|
|||||||
*/
|
*/
|
||||||
public ExpandableListView getExpandableListView() {
|
public ExpandableListView getExpandableListView() {
|
||||||
ensureList();
|
ensureList();
|
||||||
return mList;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the ExpandableListAdapter associated with this activity's ExpandableListView.
|
* Get the ExpandableListAdapter associated with this activity's ExpandableListView.
|
||||||
*/
|
*/
|
||||||
public ExpandableListAdapter getExpandableListAdapter() {
|
public ExpandableListAdapter getExpandableListAdapter() {
|
||||||
return mAdapter;
|
return adapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ensureList() {
|
private void ensureList() {
|
||||||
if (mList != null) {
|
if (list != null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setContentView(R.layout.expandable_list_content);
|
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.
|
* @return The ID of the currently selected group or child.
|
||||||
*/
|
*/
|
||||||
public long getSelectedId() {
|
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.
|
* @return A packed position representation containing the currently selected group or child's position and type.
|
||||||
*/
|
*/
|
||||||
public long getSelectedPosition() {
|
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.
|
* Whether the child's group should be expanded if it is collapsed.
|
||||||
* @return Whether the selection was successfully set on the child.
|
* @return Whether the selection was successfully set on the child.
|
||||||
*/
|
*/
|
||||||
public boolean setSelectedChild(int groupPosition, int childPosition, boolean shouldExpandGroup) {
|
public boolean setSelectedChild(final int groupPosition, final int childPosition, final boolean shouldExpandGroup) {
|
||||||
return mList.setSelectedChild(groupPosition, childPosition, shouldExpandGroup);
|
return list.setSelectedChild(groupPosition, childPosition, shouldExpandGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -292,8 +295,8 @@ public class ExpandableListActivity extends AppCompatActivity implements
|
|||||||
* @param groupPosition
|
* @param groupPosition
|
||||||
* The position of the group that should be selected.
|
* The position of the group that should be selected.
|
||||||
*/
|
*/
|
||||||
public void setSelectedGroup(int groupPosition) {
|
public void setSelectedGroup(final int groupPosition) {
|
||||||
mList.setSelectedGroup(groupPosition);
|
list.setSelectedGroup(groupPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import android.bluetooth.BluetoothGatt;
|
|||||||
import android.bluetooth.BluetoothGattCharacteristic;
|
import android.bluetooth.BluetoothGattCharacteristic;
|
||||||
import android.bluetooth.BluetoothGattService;
|
import android.bluetooth.BluetoothGattService;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
|
import androidx.annotation.IntRange;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
@@ -23,16 +25,15 @@ import no.nordicsemi.android.nrftoolbox.profile.LoggableBleManager;
|
|||||||
* @param <T> The profile callbacks type.
|
* @param <T> The profile callbacks type.
|
||||||
* @see BleManager
|
* @see BleManager
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("WeakerAccess")
|
|
||||||
public abstract class BatteryManager<T extends BatteryManagerCallbacks> extends LoggableBleManager<T> {
|
public abstract class BatteryManager<T extends BatteryManagerCallbacks> extends LoggableBleManager<T> {
|
||||||
/** Battery Service UUID. */
|
/** Battery Service UUID. */
|
||||||
private final static UUID BATTERY_SERVICE_UUID = UUID.fromString("0000180F-0000-1000-8000-00805f9b34fb");
|
private final static UUID BATTERY_SERVICE_UUID = UUID.fromString("0000180F-0000-1000-8000-00805f9b34fb");
|
||||||
/** Battery Level characteristic UUID. */
|
/** Battery Level characteristic UUID. */
|
||||||
private final static UUID BATTERY_LEVEL_CHARACTERISTIC_UUID = UUID.fromString("00002A19-0000-1000-8000-00805f9b34fb");
|
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. */
|
/** Last received Battery Level value. */
|
||||||
private Integer mBatteryLevel;
|
private Integer batteryLevel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The manager constructor.
|
* The manager constructor.
|
||||||
@@ -43,12 +44,13 @@ public abstract class BatteryManager<T extends BatteryManagerCallbacks> extends
|
|||||||
super(context);
|
super(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataReceivedCallback mBatteryLevelDataCallback = new BatteryLevelDataCallback() {
|
private DataReceivedCallback batteryLevelDataCallback = new BatteryLevelDataCallback() {
|
||||||
@Override
|
@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 + "%");
|
log(LogContract.Log.Level.APPLICATION,"Battery Level received: " + batteryLevel + "%");
|
||||||
mBatteryLevel = batteryLevel;
|
BatteryManager.this.batteryLevel = batteryLevel;
|
||||||
mCallbacks.onBatteryLevelChanged(device, batteryLevel);
|
callbacks.onBatteryLevelChanged(device, batteryLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -59,8 +61,8 @@ public abstract class BatteryManager<T extends BatteryManagerCallbacks> extends
|
|||||||
|
|
||||||
public void readBatteryLevelCharacteristic() {
|
public void readBatteryLevelCharacteristic() {
|
||||||
if (isConnected()) {
|
if (isConnected()) {
|
||||||
readCharacteristic(mBatteryLevelCharacteristic)
|
readCharacteristic(batteryLevelCharacteristic)
|
||||||
.with(mBatteryLevelDataCallback)
|
.with(batteryLevelDataCallback)
|
||||||
.fail((device, status) -> log(Log.WARN,"Battery Level characteristic not found"))
|
.fail((device, status) -> log(Log.WARN,"Battery Level characteristic not found"))
|
||||||
.enqueue();
|
.enqueue();
|
||||||
}
|
}
|
||||||
@@ -69,9 +71,9 @@ public abstract class BatteryManager<T extends BatteryManagerCallbacks> extends
|
|||||||
public void enableBatteryLevelCharacteristicNotifications() {
|
public void enableBatteryLevelCharacteristicNotifications() {
|
||||||
if (isConnected()) {
|
if (isConnected()) {
|
||||||
// If the Battery Level characteristic is null, the request will be ignored
|
// If the Battery Level characteristic is null, the request will be ignored
|
||||||
setNotificationCallback(mBatteryLevelCharacteristic)
|
setNotificationCallback(batteryLevelCharacteristic)
|
||||||
.with(mBatteryLevelDataCallback);
|
.with(batteryLevelDataCallback);
|
||||||
enableNotifications(mBatteryLevelCharacteristic)
|
enableNotifications(batteryLevelCharacteristic)
|
||||||
.done(device -> log(Log.INFO, "Battery Level notifications enabled"))
|
.done(device -> log(Log.INFO, "Battery Level notifications enabled"))
|
||||||
.fail((device, status) -> log(Log.WARN, "Battery Level characteristic not found"))
|
.fail((device, status) -> log(Log.WARN, "Battery Level characteristic not found"))
|
||||||
.enqueue();
|
.enqueue();
|
||||||
@@ -83,7 +85,7 @@ public abstract class BatteryManager<T extends BatteryManagerCallbacks> extends
|
|||||||
*/
|
*/
|
||||||
public void disableBatteryLevelCharacteristicNotifications() {
|
public void disableBatteryLevelCharacteristicNotifications() {
|
||||||
if (isConnected()) {
|
if (isConnected()) {
|
||||||
disableNotifications(mBatteryLevelCharacteristic)
|
disableNotifications(batteryLevelCharacteristic)
|
||||||
.done(device -> log(Log.INFO, "Battery Level notifications disabled"))
|
.done(device -> log(Log.INFO, "Battery Level notifications disabled"))
|
||||||
.enqueue();
|
.enqueue();
|
||||||
}
|
}
|
||||||
@@ -95,7 +97,7 @@ public abstract class BatteryManager<T extends BatteryManagerCallbacks> extends
|
|||||||
* @return Battery Level value, in percent.
|
* @return Battery Level value, in percent.
|
||||||
*/
|
*/
|
||||||
public Integer getBatteryLevel() {
|
public Integer getBatteryLevel() {
|
||||||
return mBatteryLevel;
|
return batteryLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract class BatteryManagerGattCallback extends BleManagerGattCallback {
|
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) {
|
protected boolean isOptionalServiceSupported(@NonNull final BluetoothGatt gatt) {
|
||||||
final BluetoothGattService service = gatt.getService(BATTERY_SERVICE_UUID);
|
final BluetoothGattService service = gatt.getService(BATTERY_SERVICE_UUID);
|
||||||
if (service != null) {
|
if (service != null) {
|
||||||
mBatteryLevelCharacteristic = service.getCharacteristic(BATTERY_LEVEL_CHARACTERISTIC_UUID);
|
batteryLevelCharacteristic = service.getCharacteristic(BATTERY_LEVEL_CHARACTERISTIC_UUID);
|
||||||
}
|
}
|
||||||
return mBatteryLevelCharacteristic != null;
|
return batteryLevelCharacteristic != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDeviceDisconnected() {
|
protected void onDeviceDisconnected() {
|
||||||
mBatteryLevelCharacteristic = null;
|
batteryLevelCharacteristic = null;
|
||||||
mBatteryLevel = null;
|
batteryLevel = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,15 +41,15 @@ public class BPMActivity extends BleProfileActivity implements BPMManagerCallbac
|
|||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private static final String TAG = "BPMActivity";
|
private static final String TAG = "BPMActivity";
|
||||||
|
|
||||||
private TextView mSystolicView;
|
private TextView systolicView;
|
||||||
private TextView mSystolicUnitView;
|
private TextView systolicUnitView;
|
||||||
private TextView mDiastolicView;
|
private TextView diastolicView;
|
||||||
private TextView mDiastolicUnitView;
|
private TextView diastolicUnitView;
|
||||||
private TextView mMeanAPView;
|
private TextView meanAPView;
|
||||||
private TextView mMeanAPUnitView;
|
private TextView meanAPUnitView;
|
||||||
private TextView mPulseView;
|
private TextView pulseView;
|
||||||
private TextView mTimestampView;
|
private TextView timestampView;
|
||||||
private TextView mBatteryLevelView;
|
private TextView batteryLevelView;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreateView(final Bundle savedInstanceState) {
|
protected void onCreateView(final Bundle savedInstanceState) {
|
||||||
@@ -58,15 +58,15 @@ public class BPMActivity extends BleProfileActivity implements BPMManagerCallbac
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setGUI() {
|
private void setGUI() {
|
||||||
mSystolicView = findViewById(R.id.systolic);
|
systolicView = findViewById(R.id.systolic);
|
||||||
mSystolicUnitView = findViewById(R.id.systolic_unit);
|
systolicUnitView = findViewById(R.id.systolic_unit);
|
||||||
mDiastolicView = findViewById(R.id.diastolic);
|
diastolicView = findViewById(R.id.diastolic);
|
||||||
mDiastolicUnitView = findViewById(R.id.diastolic_unit);
|
diastolicUnitView = findViewById(R.id.diastolic_unit);
|
||||||
mMeanAPView = findViewById(R.id.mean_ap);
|
meanAPView = findViewById(R.id.mean_ap);
|
||||||
mMeanAPUnitView = findViewById(R.id.mean_ap_unit);
|
meanAPUnitView = findViewById(R.id.mean_ap_unit);
|
||||||
mPulseView = findViewById(R.id.pulse);
|
pulseView = findViewById(R.id.pulse);
|
||||||
mTimestampView = findViewById(R.id.timestamp);
|
timestampView = findViewById(R.id.timestamp);
|
||||||
mBatteryLevelView = findViewById(R.id.battery);
|
batteryLevelView = findViewById(R.id.battery);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -92,21 +92,21 @@ public class BPMActivity extends BleProfileActivity implements BPMManagerCallbac
|
|||||||
@Override
|
@Override
|
||||||
protected LoggableBleManager<BPMManagerCallbacks> initializeManager() {
|
protected LoggableBleManager<BPMManagerCallbacks> initializeManager() {
|
||||||
final BPMManager manager = BPMManager.getBPMManager(getApplicationContext());
|
final BPMManager manager = BPMManager.getBPMManager(getApplicationContext());
|
||||||
manager.setGattCallbacks(this);
|
manager.setManagerCallbacks(this);
|
||||||
return manager;
|
return manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setDefaultUI() {
|
protected void setDefaultUI() {
|
||||||
mSystolicView.setText(R.string.not_available_value);
|
systolicView.setText(R.string.not_available_value);
|
||||||
mSystolicUnitView.setText(null);
|
systolicUnitView.setText(null);
|
||||||
mDiastolicView.setText(R.string.not_available_value);
|
diastolicView.setText(R.string.not_available_value);
|
||||||
mDiastolicUnitView.setText(null);
|
diastolicUnitView.setText(null);
|
||||||
mMeanAPView.setText(R.string.not_available_value);
|
meanAPView.setText(R.string.not_available_value);
|
||||||
mMeanAPUnitView.setText(null);
|
meanAPUnitView.setText(null);
|
||||||
mPulseView.setText(R.string.not_available_value);
|
pulseView.setText(R.string.not_available_value);
|
||||||
mTimestampView.setText(R.string.not_available);
|
timestampView.setText(R.string.not_available);
|
||||||
mBatteryLevelView.setText(R.string.not_available);
|
batteryLevelView.setText(R.string.not_available);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -122,7 +122,7 @@ public class BPMActivity extends BleProfileActivity implements BPMManagerCallbac
|
|||||||
@Override
|
@Override
|
||||||
public void onDeviceDisconnected(@NonNull final BluetoothDevice device) {
|
public void onDeviceDisconnected(@NonNull final BluetoothDevice device) {
|
||||||
super.onDeviceDisconnected(device);
|
super.onDeviceDisconnected(device);
|
||||||
runOnUiThread(() -> mBatteryLevelView.setText(R.string.not_available));
|
runOnUiThread(() -> batteryLevelView.setText(R.string.not_available));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -131,21 +131,21 @@ public class BPMActivity extends BleProfileActivity implements BPMManagerCallbac
|
|||||||
@Nullable final Float pulseRate, @Nullable final Integer userID,
|
@Nullable final Float pulseRate, @Nullable final Integer userID,
|
||||||
@Nullable final BPMStatus status, @Nullable final Calendar calendar) {
|
@Nullable final BPMStatus status, @Nullable final Calendar calendar) {
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
mSystolicView.setText(String.valueOf(systolic));
|
systolicView.setText(String.valueOf(systolic));
|
||||||
mDiastolicView.setText(String.valueOf(diastolic));
|
diastolicView.setText(String.valueOf(diastolic));
|
||||||
mMeanAPView.setText(String.valueOf(meanArterialPressure));
|
meanAPView.setText(String.valueOf(meanArterialPressure));
|
||||||
if (pulseRate != null)
|
if (pulseRate != null)
|
||||||
mPulseView.setText(String.valueOf(pulseRate));
|
pulseView.setText(String.valueOf(pulseRate));
|
||||||
else
|
else
|
||||||
mPulseView.setText(R.string.not_available_value);
|
pulseView.setText(R.string.not_available_value);
|
||||||
if (calendar != null)
|
if (calendar != null)
|
||||||
mTimestampView.setText(getString(R.string.bpm_timestamp, calendar));
|
timestampView.setText(getString(R.string.bpm_timestamp, calendar));
|
||||||
else
|
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);
|
systolicUnitView.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);
|
diastolicUnitView.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);
|
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 Float pulseRate, @Nullable final Integer userID,
|
||||||
@Nullable final BPMStatus status, @Nullable final Calendar calendar) {
|
@Nullable final BPMStatus status, @Nullable final Calendar calendar) {
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
mSystolicView.setText(String.valueOf(cuffPressure));
|
systolicView.setText(String.valueOf(cuffPressure));
|
||||||
mDiastolicView.setText(R.string.not_available_value);
|
diastolicView.setText(R.string.not_available_value);
|
||||||
mMeanAPView.setText(R.string.not_available_value);
|
meanAPView.setText(R.string.not_available_value);
|
||||||
if (pulseRate != null)
|
if (pulseRate != null)
|
||||||
mPulseView.setText(String.valueOf(pulseRate));
|
pulseView.setText(String.valueOf(pulseRate));
|
||||||
else
|
else
|
||||||
mPulseView.setText(R.string.not_available_value);
|
pulseView.setText(R.string.not_available_value);
|
||||||
if (calendar != null)
|
if (calendar != null)
|
||||||
mTimestampView.setText(getString(R.string.bpm_timestamp, calendar));
|
timestampView.setText(getString(R.string.bpm_timestamp, calendar));
|
||||||
else
|
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);
|
systolicUnitView.setText(unit == IntermediateCuffPressureCallback.UNIT_mmHg ? R.string.bpm_unit_mmhg : R.string.bpm_unit_kpa);
|
||||||
mDiastolicUnitView.setText(null);
|
diastolicUnitView.setText(null);
|
||||||
mMeanAPUnitView.setText(null);
|
meanAPUnitView.setText(null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) {
|
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)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ public class BPMManager extends BatteryManager<BPMManagerCallbacks> {
|
|||||||
/** Intermediate Cuff Pressure characteristic UUID. */
|
/** Intermediate Cuff Pressure characteristic UUID. */
|
||||||
private static final UUID ICP_CHARACTERISTIC_UUID = UUID.fromString("00002A36-0000-1000-8000-00805f9b34fb");
|
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;
|
private static BPMManager managerInstance = null;
|
||||||
|
|
||||||
@@ -71,20 +71,20 @@ public class BPMManager extends BatteryManager<BPMManagerCallbacks> {
|
|||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
protected BatteryManagerGattCallback getGattCallback() {
|
protected BatteryManagerGattCallback getGattCallback() {
|
||||||
return mGattCallback;
|
return gattCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BluetoothGatt callbacks for connection/disconnection, service discovery,
|
* BluetoothGatt callbacks for connection/disconnection, service discovery,
|
||||||
* receiving notification, etc.
|
* receiving notification, etc.
|
||||||
*/
|
*/
|
||||||
private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() {
|
private final BatteryManagerGattCallback gattCallback = new BatteryManagerGattCallback() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initialize() {
|
protected void initialize() {
|
||||||
super.initialize();
|
super.initialize();
|
||||||
|
|
||||||
setNotificationCallback(mICPCharacteristic)
|
setNotificationCallback(icpCharacteristic)
|
||||||
.with(new IntermediateCuffPressureDataCallback() {
|
.with(new IntermediateCuffPressureDataCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
|
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,
|
final float cuffPressure, final int unit,
|
||||||
@Nullable final Float pulseRate, @Nullable final Integer userID,
|
@Nullable final Float pulseRate, @Nullable final Integer userID,
|
||||||
@Nullable final BPMStatus status, @Nullable final Calendar calendar) {
|
@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
|
@Override
|
||||||
@@ -107,7 +107,7 @@ public class BPMManager extends BatteryManager<BPMManagerCallbacks> {
|
|||||||
log(Log.WARN, "Invalid ICP data received: " + data);
|
log(Log.WARN, "Invalid ICP data received: " + data);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
setIndicationCallback(mBPMCharacteristic)
|
setIndicationCallback(bpmCharacteristic)
|
||||||
.with(new BloodPressureMeasurementDataCallback() {
|
.with(new BloodPressureMeasurementDataCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
|
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,
|
final int unit, @Nullable final Float pulseRate,
|
||||||
@Nullable final Integer userID, @Nullable final BPMStatus status,
|
@Nullable final Integer userID, @Nullable final BPMStatus status,
|
||||||
@Nullable final Calendar calendar) {
|
@Nullable final Calendar calendar) {
|
||||||
mCallbacks.onBloodPressureMeasurementReceived(device, systolic, diastolic,
|
callbacks.onBloodPressureMeasurementReceived(device, systolic, diastolic,
|
||||||
meanArterialPressure, unit, pulseRate, userID, status, calendar);
|
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,
|
.fail((device, status) -> log(Log.WARN,
|
||||||
"Intermediate Cuff Pressure characteristic not found"))
|
"Intermediate Cuff Pressure characteristic not found"))
|
||||||
.enqueue();
|
.enqueue();
|
||||||
enableIndications(mBPMCharacteristic).enqueue();
|
enableIndications(bpmCharacteristic).enqueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) {
|
protected boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) {
|
||||||
final BluetoothGattService service = gatt.getService(BP_SERVICE_UUID);
|
final BluetoothGattService service = gatt.getService(BP_SERVICE_UUID);
|
||||||
if (service != null) {
|
if (service != null) {
|
||||||
mBPMCharacteristic = service.getCharacteristic(BPM_CHARACTERISTIC_UUID);
|
bpmCharacteristic = service.getCharacteristic(BPM_CHARACTERISTIC_UUID);
|
||||||
mICPCharacteristic = service.getCharacteristic(ICP_CHARACTERISTIC_UUID);
|
icpCharacteristic = service.getCharacteristic(ICP_CHARACTERISTIC_UUID);
|
||||||
}
|
}
|
||||||
return mBPMCharacteristic != null;
|
return bpmCharacteristic != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean isOptionalServiceSupported(@NonNull final BluetoothGatt gatt) {
|
protected boolean isOptionalServiceSupported(@NonNull final BluetoothGatt gatt) {
|
||||||
super.isOptionalServiceSupported(gatt); // ignore the result of this
|
super.isOptionalServiceSupported(gatt); // ignore the result of this
|
||||||
return mICPCharacteristic != null;
|
return icpCharacteristic != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDeviceDisconnected() {
|
protected void onDeviceDisconnected() {
|
||||||
mICPCharacteristic = null;
|
icpCharacteristic = null;
|
||||||
mBPMCharacteristic = null;
|
bpmCharacteristic = null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
@@ -45,13 +47,13 @@ import no.nordicsemi.android.nrftoolbox.profile.BleProfileServiceReadyActivity;
|
|||||||
import no.nordicsemi.android.nrftoolbox.proximity.ProximityService;
|
import no.nordicsemi.android.nrftoolbox.proximity.ProximityService;
|
||||||
|
|
||||||
public class CGMSActivity extends BleProfileServiceReadyActivity<CGMService.CGMSBinder> implements PopupMenu.OnMenuItemClickListener {
|
public class CGMSActivity extends BleProfileServiceReadyActivity<CGMService.CGMSBinder> implements PopupMenu.OnMenuItemClickListener {
|
||||||
private View mControlPanelStd;
|
private View controlPanelStd;
|
||||||
private View mControlPanelAbort;
|
private View controlPanelAbort;
|
||||||
private ListView mRecordsListView;
|
private ListView recordsListView;
|
||||||
private TextView mBatteryLevelView;
|
private TextView batteryLevelView;
|
||||||
private CGMSRecordsAdapter mCgmsRecordsAdapter;
|
private CGMSRecordsAdapter cgmsRecordsAdapter;
|
||||||
|
|
||||||
private CGMService.CGMSBinder mBinder;
|
private CGMService.CGMSBinder binder;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreateView(Bundle savedInstanceState) {
|
protected void onCreateView(Bundle savedInstanceState) {
|
||||||
@@ -61,32 +63,32 @@ public class CGMSActivity extends BleProfileServiceReadyActivity<CGMService.CGMS
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onInitialize(Bundle savedInstanceState) {
|
protected void onInitialize(Bundle savedInstanceState) {
|
||||||
LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, makeIntentFilter());
|
LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, makeIntentFilter());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setGUI() {
|
private void setGUI() {
|
||||||
mRecordsListView = findViewById(R.id.list);
|
recordsListView = findViewById(R.id.list);
|
||||||
mControlPanelStd = findViewById(R.id.cgms_control_std);
|
controlPanelStd = findViewById(R.id.cgms_control_std);
|
||||||
mControlPanelAbort = findViewById(R.id.cgms_control_abort);
|
controlPanelAbort = findViewById(R.id.cgms_control_abort);
|
||||||
mBatteryLevelView = findViewById(R.id.battery);
|
batteryLevelView = findViewById(R.id.battery);
|
||||||
|
|
||||||
findViewById(R.id.action_last).setOnClickListener(v -> {
|
findViewById(R.id.action_last).setOnClickListener(v -> {
|
||||||
clearRecords();
|
clearRecords();
|
||||||
if (mBinder != null) {
|
if (binder != null) {
|
||||||
mBinder.clear();
|
binder.clear();
|
||||||
mBinder.getLastRecord();
|
binder.getLastRecord();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
findViewById(R.id.action_all).setOnClickListener(v -> {
|
findViewById(R.id.action_all).setOnClickListener(v -> {
|
||||||
clearRecords();
|
clearRecords();
|
||||||
if (mBinder != null) {
|
if (binder != null) {
|
||||||
clearRecords();
|
clearRecords();
|
||||||
mBinder.getAllRecords();
|
binder.getAllRecords();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
findViewById(R.id.action_abort).setOnClickListener(v -> {
|
findViewById(R.id.action_abort).setOnClickListener(v -> {
|
||||||
if (mBinder != null) {
|
if (binder != null) {
|
||||||
mBinder.abort();
|
binder.abort();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -101,27 +103,27 @@ public class CGMSActivity extends BleProfileServiceReadyActivity<CGMService.CGMS
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void loadAdapter(SparseArray<CGMSRecord> records) {
|
private void loadAdapter(SparseArray<CGMSRecord> records) {
|
||||||
mCgmsRecordsAdapter.clear();
|
cgmsRecordsAdapter.clear();
|
||||||
for (int i = 0; i < records.size(); i++) {
|
for (int i = 0; i < records.size(); i++) {
|
||||||
mCgmsRecordsAdapter.addItem(records.valueAt(i));
|
cgmsRecordsAdapter.addItem(records.valueAt(i));
|
||||||
}
|
}
|
||||||
mCgmsRecordsAdapter.notifyDataSetChanged();
|
cgmsRecordsAdapter.notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver);
|
LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onServiceBound(final CGMService.CGMSBinder binder) {
|
protected void onServiceBound(final CGMService.CGMSBinder binder) {
|
||||||
mBinder = binder;
|
this.binder = binder;
|
||||||
final SparseArray<CGMSRecord> cgmsRecords = binder.getRecords();
|
final SparseArray<CGMSRecord> cgmsRecords = binder.getRecords();
|
||||||
if (cgmsRecords != null && cgmsRecords.size() > 0) {
|
if (cgmsRecords != null && cgmsRecords.size() > 0) {
|
||||||
if (mCgmsRecordsAdapter == null) {
|
if (cgmsRecordsAdapter == null) {
|
||||||
mCgmsRecordsAdapter = new CGMSRecordsAdapter(CGMSActivity.this);
|
cgmsRecordsAdapter = new CGMSRecordsAdapter(CGMSActivity.this);
|
||||||
mRecordsListView.setAdapter(mCgmsRecordsAdapter);
|
recordsListView.setAdapter(cgmsRecordsAdapter);
|
||||||
}
|
}
|
||||||
loadAdapter(cgmsRecords);
|
loadAdapter(cgmsRecords);
|
||||||
}
|
}
|
||||||
@@ -129,7 +131,7 @@ public class CGMSActivity extends BleProfileServiceReadyActivity<CGMService.CGMS
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onServiceUnbound() {
|
protected void onServiceUnbound() {
|
||||||
mBinder = null;
|
binder = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -158,31 +160,31 @@ public class CGMSActivity extends BleProfileServiceReadyActivity<CGMService.CGMS
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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
|
// this may notify user or show some views
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setOperationInProgress(final boolean progress) {
|
private void setOperationInProgress(final boolean progress) {
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
// setSupportProgressBarIndeterminateVisibility(progress);
|
// setSupportProgressBarIndeterminateVisibility(progress);
|
||||||
mControlPanelStd.setVisibility(!progress ? View.VISIBLE : View.GONE);
|
controlPanelStd.setVisibility(!progress ? View.VISIBLE : View.GONE);
|
||||||
mControlPanelAbort.setVisibility(progress ? View.VISIBLE : View.GONE);
|
controlPanelAbort.setVisibility(progress ? View.VISIBLE : View.GONE);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onBatteryLevelChanged(final BluetoothDevice device, final int value) {
|
public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int value) {
|
||||||
mBatteryLevelView.setText(getString(R.string.battery, value));
|
batteryLevelView.setText(getString(R.string.battery, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceDisconnected(final BluetoothDevice device) {
|
public void onDeviceDisconnected(@NonNull final BluetoothDevice device) {
|
||||||
super.onDeviceDisconnected(device);
|
super.onDeviceDisconnected(device);
|
||||||
setOperationInProgress(false);
|
setOperationInProgress(false);
|
||||||
mBatteryLevelView.setText(R.string.not_available);
|
batteryLevelView.setText(R.string.not_available);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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);
|
super.onError(device, message, errorCode);
|
||||||
setOperationInProgress(false);
|
setOperationInProgress(false);
|
||||||
}
|
}
|
||||||
@@ -190,40 +192,40 @@ public class CGMSActivity extends BleProfileServiceReadyActivity<CGMService.CGMS
|
|||||||
@Override
|
@Override
|
||||||
protected void setDefaultUI() {
|
protected void setDefaultUI() {
|
||||||
clearRecords();
|
clearRecords();
|
||||||
mBatteryLevelView.setText(R.string.not_available);
|
batteryLevelView.setText(R.string.not_available);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onMenuItemClick(MenuItem menuItem) {
|
public boolean onMenuItemClick(MenuItem menuItem) {
|
||||||
switch (menuItem.getItemId()) {
|
switch (menuItem.getItemId()) {
|
||||||
case R.id.action_refresh:
|
case R.id.action_refresh:
|
||||||
if(mBinder != null)
|
if(binder != null)
|
||||||
mBinder.refreshRecords();
|
binder.refreshRecords();
|
||||||
break;
|
break;
|
||||||
case R.id.action_first:
|
case R.id.action_first:
|
||||||
if (mBinder != null)
|
if (binder != null)
|
||||||
mBinder.getFirstRecord();
|
binder.getFirstRecord();
|
||||||
break;
|
break;
|
||||||
case R.id.action_clear:
|
case R.id.action_clear:
|
||||||
if (mBinder != null)
|
if (binder != null)
|
||||||
mBinder.clear();
|
binder.clear();
|
||||||
break;
|
break;
|
||||||
case R.id.action_delete_all:
|
case R.id.action_delete_all:
|
||||||
if (mBinder != null)
|
if (binder != null)
|
||||||
mBinder.deleteAllRecords();
|
binder.deleteAllRecords();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearRecords() {
|
private void clearRecords() {
|
||||||
if (mCgmsRecordsAdapter != null) {
|
if (cgmsRecordsAdapter != null) {
|
||||||
mCgmsRecordsAdapter.clear();
|
cgmsRecordsAdapter.clear();
|
||||||
mCgmsRecordsAdapter.notifyDataSetChanged();
|
cgmsRecordsAdapter.notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
|
private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(final Context context, final Intent intent) {
|
public void onReceive(final Context context, final Intent intent) {
|
||||||
final String action = intent.getAction();
|
final String action = intent.getAction();
|
||||||
@@ -232,12 +234,12 @@ public class CGMSActivity extends BleProfileServiceReadyActivity<CGMService.CGMS
|
|||||||
switch (action) {
|
switch (action) {
|
||||||
case CGMService.BROADCAST_NEW_CGMS_VALUE: {
|
case CGMService.BROADCAST_NEW_CGMS_VALUE: {
|
||||||
CGMSRecord cgmsRecord = intent.getExtras().getParcelable(CGMService.EXTRA_CGMS_RECORD);
|
CGMSRecord cgmsRecord = intent.getExtras().getParcelable(CGMService.EXTRA_CGMS_RECORD);
|
||||||
if (mCgmsRecordsAdapter == null) {
|
if (cgmsRecordsAdapter == null) {
|
||||||
mCgmsRecordsAdapter = new CGMSRecordsAdapter(CGMSActivity.this);
|
cgmsRecordsAdapter = new CGMSRecordsAdapter(CGMSActivity.this);
|
||||||
mRecordsListView.setAdapter(mCgmsRecordsAdapter);
|
recordsListView.setAdapter(cgmsRecordsAdapter);
|
||||||
}
|
}
|
||||||
mCgmsRecordsAdapter.addItem(cgmsRecord);
|
cgmsRecordsAdapter.addItem(cgmsRecord);
|
||||||
mCgmsRecordsAdapter.notifyDataSetChanged();
|
cgmsRecordsAdapter.notifyDataSetChanged();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CGMService.BROADCAST_DATA_SET_CLEAR:
|
case CGMService.BROADCAST_DATA_SET_CLEAR:
|
||||||
|
|||||||
@@ -22,18 +22,19 @@
|
|||||||
|
|
||||||
package no.nordicsemi.android.nrftoolbox.cgms;
|
package no.nordicsemi.android.nrftoolbox.cgms;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.bluetooth.BluetoothGatt;
|
import android.bluetooth.BluetoothGatt;
|
||||||
import android.bluetooth.BluetoothGattCharacteristic;
|
import android.bluetooth.BluetoothGattCharacteristic;
|
||||||
import android.bluetooth.BluetoothGattService;
|
import android.bluetooth.BluetoothGattService;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
|
|
||||||
import java.util.UUID;
|
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.RecordAccessControlPointDataCallback;
|
||||||
import no.nordicsemi.android.ble.common.callback.cgm.CGMFeatureDataCallback;
|
import no.nordicsemi.android.ble.common.callback.cgm.CGMFeatureDataCallback;
|
||||||
import no.nordicsemi.android.ble.common.callback.cgm.CGMSpecificOpsControlPointDataCallback;
|
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.CGMSpecificOpsControlPointParser;
|
||||||
import no.nordicsemi.android.nrftoolbox.parser.RecordAccessControlPointParser;
|
import no.nordicsemi.android.nrftoolbox.parser.RecordAccessControlPointParser;
|
||||||
|
|
||||||
public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
|
class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
|
||||||
/** Cycling Speed and Cadence service UUID. */
|
/** 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_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_FEATURE_UUID = UUID.fromString("00002AA8-0000-1000-8000-00805f9b34fb");
|
||||||
private static final UUID CGM_MEASUREMENT_UUID = UUID.fromString("00002AA7-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. */
|
/** Record Access Control Point characteristic UUID. */
|
||||||
private static final UUID RACP_UUID = UUID.fromString("00002A52-0000-1000-8000-00805f9b34fb");
|
private static final UUID RACP_UUID = UUID.fromString("00002A52-0000-1000-8000-00805f9b34fb");
|
||||||
|
|
||||||
private BluetoothGattCharacteristic mCGMStatusCharacteristic;
|
private BluetoothGattCharacteristic cgmStatusCharacteristic;
|
||||||
private BluetoothGattCharacteristic mCGMFeatureCharacteristic;
|
private BluetoothGattCharacteristic cgmFeatureCharacteristic;
|
||||||
private BluetoothGattCharacteristic mCGMMeasurementCharacteristic;
|
private BluetoothGattCharacteristic cgmMeasurementCharacteristic;
|
||||||
private BluetoothGattCharacteristic mCGMSpecificOpsControlPointCharacteristic;
|
private BluetoothGattCharacteristic cgmSpecificOpsControlPointCharacteristic;
|
||||||
private BluetoothGattCharacteristic mRecordAccessControlPointCharacteristic;
|
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. */
|
/** 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
|
* A flag set when records has been requested using RACP. This is to distinguish CGM packets
|
||||||
* received as continuous measurements or requested.
|
* 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
|
* The timestamp when the session has started. This is needed to display the user facing
|
||||||
* times of samples.
|
* times of samples.
|
||||||
*/
|
*/
|
||||||
private long mSessionStartTime;
|
private long sessionStartTime;
|
||||||
|
|
||||||
CGMSManager(final Context context) {
|
CGMSManager(final Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
@@ -86,14 +87,14 @@ public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
|
|||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
protected BatteryManagerGattCallback getGattCallback() {
|
protected BatteryManagerGattCallback getGattCallback() {
|
||||||
return mGattCallback;
|
return gattCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BluetoothGatt callbacks for connection/disconnection, service discovery,
|
* BluetoothGatt callbacks for connection/disconnection, service discovery,
|
||||||
* receiving notification, etc.
|
* receiving notification, etc.
|
||||||
*/
|
*/
|
||||||
private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() {
|
private final BatteryManagerGattCallback gattCallback = new BatteryManagerGattCallback() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initialize() {
|
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.
|
// Read CGM Feature characteristic, mainly to see if the device supports E2E CRC.
|
||||||
// This is not supported in the experimental CGMS from the SDK.
|
// This is not supported in the experimental CGMS from the SDK.
|
||||||
readCharacteristic(mCGMFeatureCharacteristic)
|
readCharacteristic(cgmFeatureCharacteristic)
|
||||||
.with(new CGMFeatureDataCallback() {
|
.with(new CGMFeatureDataCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onContinuousGlucoseMonitorFeaturesReceived(@NonNull final BluetoothDevice device, @NonNull final CGMFeatures features,
|
public void onContinuousGlucoseMonitorFeaturesReceived(@NonNull final BluetoothDevice device, @NonNull final CGMFeatures features,
|
||||||
final int type, final int sampleLocation, final boolean secured) {
|
final int type, final int sampleLocation, final boolean secured) {
|
||||||
mSecured = features.e2eCrcSupported;
|
CGMSManager.this.secured = features.e2eCrcSupported;
|
||||||
log(LogContract.Log.Level.APPLICATION, "E2E CRC feature " + (mSecured ? "supported" : "not supported"));
|
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"))
|
.fail((device, status) -> log(Log.WARN, "Could not read CGM Feature characteristic"))
|
||||||
.enqueue();
|
.enqueue();
|
||||||
|
|
||||||
// Check if the session is already started. This is not supported in the experimental CGMS from the SDK.
|
// 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() {
|
.with(new CGMStatusDataCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onContinuousGlucoseMonitorStatusChanged(@NonNull final BluetoothDevice device, @NonNull final CGMStatus status, final int timeOffset, final boolean secured) {
|
public void onContinuousGlucoseMonitorStatusChanged(@NonNull final BluetoothDevice device, @NonNull final CGMStatus status, final int timeOffset, final boolean secured) {
|
||||||
if (!status.sessionStopped) {
|
if (!status.sessionStopped) {
|
||||||
mSessionStartTime = System.currentTimeMillis() - timeOffset * 60000L;
|
sessionStartTime = System.currentTimeMillis() - timeOffset * 60000L;
|
||||||
log(LogContract.Log.Level.APPLICATION, "Session already started");
|
log(LogContract.Log.Level.APPLICATION, "Session already started");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -129,7 +130,7 @@ public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
|
|||||||
.enqueue();
|
.enqueue();
|
||||||
|
|
||||||
// Set notification and indication callbacks
|
// Set notification and indication callbacks
|
||||||
setNotificationCallback(mCGMMeasurementCharacteristic)
|
setNotificationCallback(cgmMeasurementCharacteristic)
|
||||||
.with(new ContinuousGlucoseMeasurementDataCallback() {
|
.with(new ContinuousGlucoseMeasurementDataCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
|
public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
|
||||||
@@ -147,16 +148,16 @@ public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
|
|||||||
final boolean secured) {
|
final boolean secured) {
|
||||||
// If the CGM Status characteristic has not been read and the session was already started before,
|
// 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.
|
// estimate the Session Start Time by subtracting timeOffset minutes from the current timestamp.
|
||||||
if (mSessionStartTime == 0 && !mRecordAccessRequestInProgress) {
|
if (sessionStartTime == 0 && !recordAccessRequestInProgress) {
|
||||||
mSessionStartTime = System.currentTimeMillis() - timeOffset * 60000L;
|
sessionStartTime = System.currentTimeMillis() - timeOffset * 60000L;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the sample timestamp based on the Session Start Time
|
// 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);
|
final CGMSRecord record = new CGMSRecord(timeOffset, glucoseConcentration, timestamp);
|
||||||
mRecords.put(record.sequenceNumber, record);
|
records.put(record.sequenceNumber, record);
|
||||||
mCallbacks.onCGMValueReceived(device, record);
|
callbacks.onCGMValueReceived(device, record);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -166,7 +167,7 @@ public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
setIndicationCallback(mCGMSpecificOpsControlPointCharacteristic)
|
setIndicationCallback(cgmSpecificOpsControlPointCharacteristic)
|
||||||
.with(new CGMSpecificOpsControlPointDataCallback() {
|
.with(new CGMSpecificOpsControlPointDataCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
|
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);
|
super.onDataReceived(device, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SwitchIntDef")
|
||||||
@Override
|
@Override
|
||||||
public void onCGMSpecificOpsOperationCompleted(@NonNull final BluetoothDevice device,
|
public void onCGMSpecificOpsOperationCompleted(@NonNull final BluetoothDevice device,
|
||||||
final int requestCode, final boolean secured) {
|
@CGMOpCode final int requestCode,
|
||||||
|
final boolean secured) {
|
||||||
switch (requestCode) {
|
switch (requestCode) {
|
||||||
case CGM_OP_CODE_START_SESSION:
|
case CGM_OP_CODE_START_SESSION:
|
||||||
mSessionStartTime = System.currentTimeMillis();
|
sessionStartTime = System.currentTimeMillis();
|
||||||
break;
|
break;
|
||||||
case CGM_OP_CODE_STOP_SESSION:
|
case CGM_OP_CODE_STOP_SESSION:
|
||||||
mSessionStartTime = 0;
|
sessionStartTime = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SwitchIntDef")
|
||||||
@SuppressWarnings("StatementWithEmptyBody")
|
@SuppressWarnings("StatementWithEmptyBody")
|
||||||
@Override
|
@Override
|
||||||
public void onCGMSpecificOpsOperationError(@NonNull final BluetoothDevice device,
|
public void onCGMSpecificOpsOperationError(@NonNull final BluetoothDevice device,
|
||||||
final int requestCode, final int errorCode,
|
@CGMOpCode final int requestCode,
|
||||||
|
@CGMErrorCode final int errorCode,
|
||||||
final boolean secured) {
|
final boolean secured) {
|
||||||
switch (requestCode) {
|
switch (requestCode) {
|
||||||
case CGM_OP_CODE_START_SESSION:
|
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.
|
// packet is received based on it's Time Offset.
|
||||||
}
|
}
|
||||||
case CGM_OP_CODE_STOP_SESSION:
|
case CGM_OP_CODE_STOP_SESSION:
|
||||||
mSessionStartTime = 0;
|
sessionStartTime = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -214,7 +219,7 @@ public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
setIndicationCallback(mRecordAccessControlPointCharacteristic)
|
setIndicationCallback(recordAccessControlPointCharacteristic)
|
||||||
.with(new RecordAccessControlPointDataCallback() {
|
.with(new RecordAccessControlPointDataCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
|
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);
|
super.onDataReceived(device, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SwitchIntDef")
|
||||||
@Override
|
@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) {
|
switch (requestCode) {
|
||||||
case RACP_OP_CODE_ABORT_OPERATION:
|
case RACP_OP_CODE_ABORT_OPERATION:
|
||||||
mCallbacks.onOperationAborted(device);
|
callbacks.onOperationAborted(device);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
mRecordAccessRequestInProgress = false;
|
recordAccessRequestInProgress = false;
|
||||||
mCallbacks.onOperationCompleted(device);
|
callbacks.onOperationCompleted(device);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRecordAccessOperationCompletedWithNoRecordsFound(@NonNull final BluetoothDevice device,
|
public void onRecordAccessOperationCompletedWithNoRecordsFound(@NonNull final BluetoothDevice device,
|
||||||
final int requestCode) {
|
@RACPOpCode final int requestCode) {
|
||||||
mRecordAccessRequestInProgress = false;
|
recordAccessRequestInProgress = false;
|
||||||
mCallbacks.onOperationCompleted(device);
|
callbacks.onOperationCompleted(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNumberOfRecordsReceived(@NonNull final BluetoothDevice device, final int numberOfRecords) {
|
public void onNumberOfRecordsReceived(@NonNull final BluetoothDevice device, final int numberOfRecords) {
|
||||||
mCallbacks.onNumberOfRecordsRequested(device, numberOfRecords);
|
callbacks.onNumberOfRecordsRequested(device, numberOfRecords);
|
||||||
if (numberOfRecords > 0) {
|
if (numberOfRecords > 0) {
|
||||||
if (mRecords.size() > 0) {
|
if (records.size() > 0) {
|
||||||
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))
|
RecordAccessControlPointData.reportStoredRecordsGreaterThenOrEqualTo(sequenceNumber))
|
||||||
.enqueue();
|
.enqueue();
|
||||||
} else {
|
} else {
|
||||||
writeCharacteristic(mRecordAccessControlPointCharacteristic,
|
writeCharacteristic(recordAccessControlPointCharacteristic,
|
||||||
RecordAccessControlPointData.reportAllStoredRecords())
|
RecordAccessControlPointData.reportAllStoredRecords())
|
||||||
.enqueue();
|
.enqueue();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mRecordAccessRequestInProgress = false;
|
recordAccessRequestInProgress = false;
|
||||||
mCallbacks.onOperationCompleted(device);
|
callbacks.onOperationCompleted(device);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRecordAccessOperationError(@NonNull final BluetoothDevice device,
|
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 + ")");
|
log(Log.WARN, "Record Access operation failed (error " + errorCode + ")");
|
||||||
if (errorCode == RACP_ERROR_OP_CODE_NOT_SUPPORTED) {
|
if (errorCode == RACP_ERROR_OP_CODE_NOT_SUPPORTED) {
|
||||||
mCallbacks.onOperationNotSupported(device);
|
callbacks.onOperationNotSupported(device);
|
||||||
} else {
|
} else {
|
||||||
mCallbacks.onOperationFailed(device);
|
callbacks.onOperationFailed(device);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Enable notifications and indications
|
// Enable notifications and indications
|
||||||
enableNotifications(mCGMMeasurementCharacteristic)
|
enableNotifications(cgmMeasurementCharacteristic)
|
||||||
.fail((device, status) -> log(Log.WARN, "Failed to enable Continuous Glucose Measurement notifications (" + status + ")"))
|
.fail((device, status) -> log(Log.WARN, "Failed to enable Continuous Glucose Measurement notifications (" + status + ")"))
|
||||||
.enqueue();
|
.enqueue();
|
||||||
enableIndications(mCGMSpecificOpsControlPointCharacteristic)
|
enableIndications(cgmSpecificOpsControlPointCharacteristic)
|
||||||
.fail((device, status) -> log(Log.WARN, "Failed to enable CGM Specific Ops Control Point indications notifications (" + status + ")"))
|
.fail((device, status) -> log(Log.WARN, "Failed to enable CGM Specific Ops Control Point indications notifications (" + status + ")"))
|
||||||
.enqueue();
|
.enqueue();
|
||||||
enableIndications(mRecordAccessControlPointCharacteristic)
|
enableIndications(recordAccessControlPointCharacteristic)
|
||||||
.fail((device, status) -> log(Log.WARN, "Failed to enabled Record Access Control Point indications (error " + status + ")"))
|
.fail((device, status) -> log(Log.WARN, "Failed to enabled Record Access Control Point indications (error " + status + ")"))
|
||||||
.enqueue();
|
.enqueue();
|
||||||
|
|
||||||
// Start Continuous Glucose session if hasn't been started before
|
// Start Continuous Glucose session if hasn't been started before
|
||||||
if (mSessionStartTime == 0L) {
|
if (sessionStartTime == 0L) {
|
||||||
writeCharacteristic(mCGMSpecificOpsControlPointCharacteristic, CGMSpecificOpsControlPointData.startSession(mSecured))
|
writeCharacteristic(cgmSpecificOpsControlPointCharacteristic, CGMSpecificOpsControlPointData.startSession(secured))
|
||||||
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + CGMSpecificOpsControlPointParser.parse(data) + "\" sent"))
|
.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 + ")"))
|
.fail((device, status) -> log(LogContract.Log.Level.ERROR, "Failed to start session (error " + status + ")"))
|
||||||
.enqueue();
|
.enqueue();
|
||||||
@@ -298,41 +307,41 @@ public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
|
|||||||
protected boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) {
|
protected boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) {
|
||||||
final BluetoothGattService service = gatt.getService(CGMS_UUID);
|
final BluetoothGattService service = gatt.getService(CGMS_UUID);
|
||||||
if (service != null) {
|
if (service != null) {
|
||||||
mCGMStatusCharacteristic = service.getCharacteristic(CGM_STATUS_UUID);
|
cgmStatusCharacteristic = service.getCharacteristic(CGM_STATUS_UUID);
|
||||||
mCGMFeatureCharacteristic = service.getCharacteristic(CGM_FEATURE_UUID);
|
cgmFeatureCharacteristic = service.getCharacteristic(CGM_FEATURE_UUID);
|
||||||
mCGMMeasurementCharacteristic = service.getCharacteristic(CGM_MEASUREMENT_UUID);
|
cgmMeasurementCharacteristic = service.getCharacteristic(CGM_MEASUREMENT_UUID);
|
||||||
mCGMSpecificOpsControlPointCharacteristic = service.getCharacteristic(CGM_OPS_CONTROL_POINT_UUID);
|
cgmSpecificOpsControlPointCharacteristic = service.getCharacteristic(CGM_OPS_CONTROL_POINT_UUID);
|
||||||
mRecordAccessControlPointCharacteristic = service.getCharacteristic(RACP_UUID);
|
recordAccessControlPointCharacteristic = service.getCharacteristic(RACP_UUID);
|
||||||
}
|
}
|
||||||
return mCGMMeasurementCharacteristic != null
|
return cgmMeasurementCharacteristic != null
|
||||||
&& mCGMSpecificOpsControlPointCharacteristic != null
|
&& cgmSpecificOpsControlPointCharacteristic != null
|
||||||
&& mRecordAccessControlPointCharacteristic != null;
|
&& recordAccessControlPointCharacteristic != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDeviceDisconnected() {
|
protected void onDeviceDisconnected() {
|
||||||
super.onDeviceDisconnected();
|
super.onDeviceDisconnected();
|
||||||
mCGMStatusCharacteristic = null;
|
cgmStatusCharacteristic = null;
|
||||||
mCGMFeatureCharacteristic = null;
|
cgmFeatureCharacteristic = null;
|
||||||
mCGMMeasurementCharacteristic = null;
|
cgmMeasurementCharacteristic = null;
|
||||||
mCGMSpecificOpsControlPointCharacteristic = null;
|
cgmSpecificOpsControlPointCharacteristic = null;
|
||||||
mRecordAccessControlPointCharacteristic = null;
|
recordAccessControlPointCharacteristic = null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of CGM records obtained from this device. The key in the array is the
|
* Returns a list of CGM records obtained from this device. The key in the array is the
|
||||||
*/
|
*/
|
||||||
public SparseArray<CGMSRecord> getRecords() {
|
SparseArray<CGMSRecord> getRecords() {
|
||||||
return mRecords;
|
return records;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears the records list locally
|
* Clears the records list locally
|
||||||
*/
|
*/
|
||||||
public void clear() {
|
void clear() {
|
||||||
mRecords.clear();
|
records.clear();
|
||||||
mCallbacks.onDatasetCleared(getBluetoothDevice());
|
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
|
* 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.
|
* Record Access Control Point indication with status code Success or other in case of error.
|
||||||
*/
|
*/
|
||||||
public void getLastRecord() {
|
void getLastRecord() {
|
||||||
if (mRecordAccessControlPointCharacteristic == null)
|
if (recordAccessControlPointCharacteristic == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
mCallbacks.onOperationStarted(getBluetoothDevice());
|
callbacks.onOperationStarted(getBluetoothDevice());
|
||||||
mRecordAccessRequestInProgress = true;
|
recordAccessRequestInProgress = true;
|
||||||
writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.reportLastStoredRecord())
|
writeCharacteristic(recordAccessControlPointCharacteristic, RecordAccessControlPointData.reportLastStoredRecord())
|
||||||
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
|
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
|
||||||
.enqueue();
|
.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
|
* 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.
|
* Record Access Control Point indication with status code Success or other in case of error.
|
||||||
*/
|
*/
|
||||||
public void getFirstRecord() {
|
void getFirstRecord() {
|
||||||
if (mRecordAccessControlPointCharacteristic == null)
|
if (recordAccessControlPointCharacteristic == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
mCallbacks.onOperationStarted(getBluetoothDevice());
|
callbacks.onOperationStarted(getBluetoothDevice());
|
||||||
mRecordAccessRequestInProgress = true;
|
recordAccessRequestInProgress = true;
|
||||||
writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.reportFirstStoredRecord())
|
writeCharacteristic(recordAccessControlPointCharacteristic, RecordAccessControlPointData.reportFirstStoredRecord())
|
||||||
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
|
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
|
||||||
.enqueue();
|
.enqueue();
|
||||||
}
|
}
|
||||||
@@ -372,11 +381,11 @@ public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
|
|||||||
/**
|
/**
|
||||||
* Sends abort operation signal to the device.
|
* Sends abort operation signal to the device.
|
||||||
*/
|
*/
|
||||||
public void abort() {
|
void abort() {
|
||||||
if (mRecordAccessControlPointCharacteristic == null)
|
if (recordAccessControlPointCharacteristic == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.abortOperation())
|
writeCharacteristic(recordAccessControlPointCharacteristic, RecordAccessControlPointData.abortOperation())
|
||||||
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
|
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
|
||||||
.enqueue();
|
.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
|
* 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.
|
* Record Access Control Point indication with status code Success or other in case of error.
|
||||||
*/
|
*/
|
||||||
public void getAllRecords() {
|
void getAllRecords() {
|
||||||
if (mRecordAccessControlPointCharacteristic == null)
|
if (recordAccessControlPointCharacteristic == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
mCallbacks.onOperationStarted(getBluetoothDevice());
|
callbacks.onOperationStarted(getBluetoothDevice());
|
||||||
mRecordAccessRequestInProgress = true;
|
recordAccessRequestInProgress = true;
|
||||||
writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.reportNumberOfAllStoredRecords())
|
writeCharacteristic(recordAccessControlPointCharacteristic, RecordAccessControlPointData.reportNumberOfAllStoredRecords())
|
||||||
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
|
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
|
||||||
.enqueue();
|
.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
|
* 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.
|
* Record Access Control Point indication with status code Success or other in case of error.
|
||||||
*/
|
*/
|
||||||
public void refreshRecords() {
|
void refreshRecords() {
|
||||||
if (mRecordAccessControlPointCharacteristic == null)
|
if (recordAccessControlPointCharacteristic == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (mRecords.size() == 0) {
|
if (records.size() == 0) {
|
||||||
getAllRecords();
|
getAllRecords();
|
||||||
} else {
|
} else {
|
||||||
mCallbacks.onOperationStarted(getBluetoothDevice());
|
callbacks.onOperationStarted(getBluetoothDevice());
|
||||||
|
|
||||||
// Obtain the last sequence number
|
// Obtain the last sequence number
|
||||||
final int sequenceNumber = mRecords.keyAt(mRecords.size() - 1) + 1;
|
final int sequenceNumber = records.keyAt(records.size() - 1) + 1;
|
||||||
mRecordAccessRequestInProgress = true;
|
recordAccessRequestInProgress = true;
|
||||||
writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.reportStoredRecordsGreaterThenOrEqualTo(sequenceNumber))
|
writeCharacteristic(recordAccessControlPointCharacteristic, RecordAccessControlPointData.reportStoredRecordsGreaterThenOrEqualTo(sequenceNumber))
|
||||||
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
|
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
|
||||||
.enqueue();
|
.enqueue();
|
||||||
// Info:
|
// 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
|
* This feature is not supported by the CGMS sample from the SDK, so monitor will answer with
|
||||||
* the Op Code Not Supported error.
|
* the Op Code Not Supported error.
|
||||||
*/
|
*/
|
||||||
public void deleteAllRecords() {
|
void deleteAllRecords() {
|
||||||
if (mRecordAccessControlPointCharacteristic == null)
|
if (recordAccessControlPointCharacteristic == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
mCallbacks.onOperationStarted(getBluetoothDevice());
|
callbacks.onOperationStarted(getBluetoothDevice());
|
||||||
writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.deleteAllStoredRecords())
|
writeCharacteristic(recordAccessControlPointCharacteristic, RecordAccessControlPointData.deleteAllStoredRecords())
|
||||||
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
|
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
|
||||||
.enqueue();
|
.enqueue();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,9 +27,9 @@ import androidx.annotation.NonNull;
|
|||||||
|
|
||||||
import no.nordicsemi.android.nrftoolbox.battery.BatteryManagerCallbacks;
|
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);
|
void onOperationStarted(final @NonNull BluetoothDevice device);
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ public interface CGMSManagerCallbacks extends BatteryManagerCallbacks {
|
|||||||
|
|
||||||
void onOperationNotSupported(final @NonNull BluetoothDevice device);
|
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);
|
void onNumberOfRecordsRequested(final @NonNull BluetoothDevice device, final int value);
|
||||||
|
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ import android.os.Parcelable;
|
|||||||
|
|
||||||
class CGMSRecord implements Parcelable{
|
class CGMSRecord implements Parcelable{
|
||||||
/** Record sequence number. */
|
/** Record sequence number. */
|
||||||
protected int sequenceNumber;
|
int sequenceNumber;
|
||||||
/** The base time of the measurement (start time + sequenceNumber of minutes). */
|
/** The base time of the measurement (start time + sequenceNumber of minutes). */
|
||||||
protected long timestamp;
|
long timestamp;
|
||||||
/** The glucose concentration in mg/dL. */
|
/** The glucose concentration in mg/dL. */
|
||||||
protected float glucoseConcentration;
|
float glucoseConcentration;
|
||||||
|
|
||||||
CGMSRecord(final int sequenceNumber, final float glucoseConcentration, final long timestamp) {
|
CGMSRecord(final int sequenceNumber, final float glucoseConcentration, final long timestamp) {
|
||||||
this.sequenceNumber = sequenceNumber;
|
this.sequenceNumber = sequenceNumber;
|
||||||
|
|||||||
@@ -13,62 +13,65 @@ import java.util.Date;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import no.nordicsemi.android.nrftoolbox.R;
|
import no.nordicsemi.android.nrftoolbox.R;
|
||||||
|
|
||||||
public class CGMSRecordsAdapter extends BaseAdapter {
|
class CGMSRecordsAdapter extends BaseAdapter {
|
||||||
private final static SimpleDateFormat mTimeFormat = new SimpleDateFormat("dd.MM.yyyy HH:mm", Locale.US);
|
private final static SimpleDateFormat timeFormat = new SimpleDateFormat("dd.MM.yyyy HH:mm", Locale.US);
|
||||||
|
|
||||||
private List<CGMSRecord> mRecords;
|
private List<CGMSRecord> records;
|
||||||
private LayoutInflater mInflater;
|
private LayoutInflater inflater;
|
||||||
|
|
||||||
public CGMSRecordsAdapter(final Context context) {
|
CGMSRecordsAdapter(@NonNull final Context context) {
|
||||||
mRecords = new ArrayList<>();
|
records = new ArrayList<>();
|
||||||
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getCount() {
|
public int getCount() {
|
||||||
return mRecords.size();
|
return records.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getItem(int i) {
|
public Object getItem(final int i) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getItemId(int i) {
|
public long getItemId(final int i) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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;
|
ViewHolder viewHolder;
|
||||||
if (convertView == null) {
|
View view = convertView;
|
||||||
convertView = mInflater.inflate(R.layout.activity_feature_cgms_item, parent, false);
|
if (view == null) {
|
||||||
|
view = inflater.inflate(R.layout.activity_feature_cgms_item, parent, false);
|
||||||
viewHolder = new ViewHolder();
|
viewHolder = new ViewHolder();
|
||||||
viewHolder.concentration = convertView.findViewById(R.id.cgms_concentration);
|
viewHolder.concentration = view.findViewById(R.id.cgms_concentration);
|
||||||
viewHolder.time = convertView.findViewById(R.id.time);
|
viewHolder.time = view.findViewById(R.id.time);
|
||||||
viewHolder.details = convertView.findViewById(R.id.details);
|
viewHolder.details = view.findViewById(R.id.details);
|
||||||
convertView.setTag(viewHolder);
|
view.setTag(viewHolder);
|
||||||
} else {
|
} 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.concentration.setText(String.valueOf(cgmsRecord.glucoseConcentration));
|
||||||
viewHolder.details.setText(viewHolder.details.getResources().getString(R.string.cgms_details, cgmsRecord.sequenceNumber));
|
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) {
|
void addItem(final CGMSRecord record) {
|
||||||
mRecords.add(record);
|
records.add(record);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clear() {
|
void clear() {
|
||||||
mRecords.clear();
|
records.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ViewHolder {
|
private static class ViewHolder {
|
||||||
|
|||||||
@@ -42,29 +42,29 @@ public class CGMService extends BleProfileService implements CGMSManagerCallback
|
|||||||
private final static int OPEN_ACTIVITY_REQ = 0;
|
private final static int OPEN_ACTIVITY_REQ = 0;
|
||||||
private final static int DISCONNECT_REQ = 1;
|
private final static int DISCONNECT_REQ = 1;
|
||||||
|
|
||||||
private CGMSManager mManager;
|
private CGMSManager manager;
|
||||||
private final LocalBinder mBinder = new CGMSBinder();
|
private final LocalBinder binder = new CGMSBinder();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This local binder is an interface for the bonded activity to operate with the RSC sensor
|
* 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.
|
* Returns all records as a sparse array where sequence number is the key.
|
||||||
*
|
*
|
||||||
* @return the records list
|
* @return the records list
|
||||||
*/
|
*/
|
||||||
public SparseArray<CGMSRecord> getRecords() {
|
SparseArray<CGMSRecord> getRecords() {
|
||||||
return mManager.getRecords();
|
return manager.getRecords();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears the records list locally
|
* Clears the records list locally
|
||||||
*/
|
*/
|
||||||
public void clear() {
|
void clear() {
|
||||||
if (mManager != null)
|
if (manager != null)
|
||||||
mManager.clear();
|
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
|
* 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.
|
* Point indication with status code ({@link CGMSManager# RESPONSE_SUCCESS} or other in case of error.
|
||||||
*/
|
*/
|
||||||
public void getFirstRecord() {
|
void getFirstRecord() {
|
||||||
if (mManager != null)
|
if (manager != null)
|
||||||
mManager.getFirstRecord();
|
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
|
* 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.
|
* Control Point indication with status code Success or other in case of error.
|
||||||
*/
|
*/
|
||||||
public void getLastRecord() {
|
void getLastRecord() {
|
||||||
if (mManager != null)
|
if (manager != null)
|
||||||
mManager.getLastRecord();
|
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
|
* 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.
|
* by Record Access Control Point indication with status code Success or other in case of error.
|
||||||
*/
|
*/
|
||||||
public void getAllRecords() {
|
void getAllRecords() {
|
||||||
if (mManager != null)
|
if (manager != null)
|
||||||
mManager.getAllRecords();
|
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
|
* characteristic as a series of notifications followed by Record Access Control Point
|
||||||
* indication with status code Success or other in case of error.
|
* indication with status code Success or other in case of error.
|
||||||
*/
|
*/
|
||||||
public void refreshRecords() {
|
void refreshRecords() {
|
||||||
if (mManager != null)
|
if (manager != null)
|
||||||
mManager.refreshRecords();
|
manager.refreshRecords();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends abort operation signal to the device
|
* Sends abort operation signal to the device
|
||||||
*/
|
*/
|
||||||
public void abort() {
|
void abort() {
|
||||||
if (mManager != null)
|
if (manager != null)
|
||||||
mManager.abort();
|
manager.abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends Delete op code with All stored records parameter. This method may not be supported by the SDK sample.
|
* Sends Delete op code with All stored records parameter. This method may not be supported by the SDK sample.
|
||||||
*/
|
*/
|
||||||
public void deleteAllRecords() {
|
void deleteAllRecords() {
|
||||||
if (mManager != null)
|
if (manager != null)
|
||||||
mManager.deleteAllRecords();
|
manager.deleteAllRecords();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected LocalBinder getBinder() {
|
protected LocalBinder getBinder() {
|
||||||
return mBinder;
|
return binder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected LoggableBleManager<CGMSManagerCallbacks> initializeManager() {
|
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();
|
super.onCreate();
|
||||||
final IntentFilter filter = new IntentFilter();
|
final IntentFilter filter = new IntentFilter();
|
||||||
filter.addAction(ACTION_DISCONNECT);
|
filter.addAction(ACTION_DISCONNECT);
|
||||||
registerReceiver(mDisconnectActionBroadcastReceiver, filter);
|
registerReceiver(disconnectActionBroadcastReceiver, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
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
|
// when user has disconnected from the sensor, we have to cancel the notification that we've created some milliseconds before using unbindService
|
||||||
stopForegroundService();
|
stopForegroundService();
|
||||||
unregisterReceiver(mDisconnectActionBroadcastReceiver);
|
unregisterReceiver(disconnectActionBroadcastReceiver);
|
||||||
|
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
}
|
}
|
||||||
@@ -199,6 +199,7 @@ public class CGMService extends BleProfileService implements CGMSManagerCallback
|
|||||||
* f.e. <code><string name="name">%s is connected</string></code>
|
* f.e. <code><string name="name">%s is connected</string></code>
|
||||||
* @param defaults signals that will be used to notify the user
|
* @param defaults signals that will be used to notify the user
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("SameParameterValue")
|
||||||
private Notification createNotification(final int messageResId, final int defaults) {
|
private Notification createNotification(final int messageResId, final int defaults) {
|
||||||
final Intent parentIntent = new Intent(this, FeaturesActivity.class);
|
final Intent parentIntent = new Intent(this, FeaturesActivity.class);
|
||||||
parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
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.
|
* 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
|
@Override
|
||||||
public void onReceive(final Context context, final Intent intent) {
|
public void onReceive(final Context context, final Intent intent) {
|
||||||
Logger.i(getLogSession(), "[Notification] Disconnect action pressed");
|
Logger.i(getLogSession(), "[Notification] Disconnect action pressed");
|
||||||
@@ -242,7 +243,7 @@ public class CGMService extends BleProfileService implements CGMSManagerCallback
|
|||||||
};
|
};
|
||||||
|
|
||||||
@Override
|
@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);
|
final Intent broadcast = new Intent(BROADCAST_NEW_CGMS_VALUE);
|
||||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||||
broadcast.putExtra(EXTRA_CGMS_RECORD, record);
|
broadcast.putExtra(EXTRA_CGMS_RECORD, record);
|
||||||
@@ -290,7 +291,7 @@ public class CGMService extends BleProfileService implements CGMSManagerCallback
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDatasetCleared(@NonNull final BluetoothDevice device) {
|
public void onDataSetCleared(@NonNull final BluetoothDevice device) {
|
||||||
final Intent broadcast = new Intent(BROADCAST_DATA_SET_CLEAR);
|
final Intent broadcast = new Intent(BROADCAST_DATA_SET_CLEAR);
|
||||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ import android.content.IntentFilter;
|
|||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
@@ -44,15 +46,15 @@ import no.nordicsemi.android.nrftoolbox.profile.BleProfileService;
|
|||||||
import no.nordicsemi.android.nrftoolbox.profile.BleProfileServiceReadyActivity;
|
import no.nordicsemi.android.nrftoolbox.profile.BleProfileServiceReadyActivity;
|
||||||
|
|
||||||
public class CSCActivity extends BleProfileServiceReadyActivity<CSCService.CSCBinder> {
|
public class CSCActivity extends BleProfileServiceReadyActivity<CSCService.CSCBinder> {
|
||||||
private TextView mSpeedView;
|
private TextView speedView;
|
||||||
private TextView mSpeedUnitView;
|
private TextView speedUnitView;
|
||||||
private TextView mCadenceView;
|
private TextView cadenceView;
|
||||||
private TextView mDistanceView;
|
private TextView distanceView;
|
||||||
private TextView mDistanceUnitView;
|
private TextView distanceUnitView;
|
||||||
private TextView mTotalDistanceView;
|
private TextView totalDistanceView;
|
||||||
private TextView mTotalDistanceUnitView;
|
private TextView totalDistanceUnitView;
|
||||||
private TextView mGearRatioView;
|
private TextView gearRatioView;
|
||||||
private TextView mBatteryLevelView;
|
private TextView batteryLevelView;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreateView(final Bundle savedInstanceState) {
|
protected void onCreateView(final Bundle savedInstanceState) {
|
||||||
@@ -62,25 +64,25 @@ public class CSCActivity extends BleProfileServiceReadyActivity<CSCService.CSCBi
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onInitialize(final Bundle savedInstanceState) {
|
protected void onInitialize(final Bundle savedInstanceState) {
|
||||||
LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, makeIntentFilter());
|
LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, makeIntentFilter());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver);
|
LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setGui() {
|
private void setGui() {
|
||||||
mSpeedView = findViewById(R.id.speed);
|
speedView = findViewById(R.id.speed);
|
||||||
mSpeedUnitView = findViewById(R.id.speed_unit);
|
speedUnitView = findViewById(R.id.speed_unit);
|
||||||
mCadenceView = findViewById(R.id.cadence);
|
cadenceView = findViewById(R.id.cadence);
|
||||||
mDistanceView = findViewById(R.id.distance);
|
distanceView = findViewById(R.id.distance);
|
||||||
mDistanceUnitView = findViewById(R.id.distance_unit);
|
distanceUnitView = findViewById(R.id.distance_unit);
|
||||||
mTotalDistanceView = findViewById(R.id.distance_total);
|
totalDistanceView = findViewById(R.id.distance_total);
|
||||||
mTotalDistanceUnitView = findViewById(R.id.distance_total_unit);
|
totalDistanceUnitView = findViewById(R.id.distance_total_unit);
|
||||||
mGearRatioView = findViewById(R.id.ratio);
|
gearRatioView = findViewById(R.id.ratio);
|
||||||
mBatteryLevelView = findViewById(R.id.battery);
|
batteryLevelView = findViewById(R.id.battery);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -91,12 +93,12 @@ public class CSCActivity extends BleProfileServiceReadyActivity<CSCService.CSCBi
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setDefaultUI() {
|
protected void setDefaultUI() {
|
||||||
mSpeedView.setText(R.string.not_available_value);
|
speedView.setText(R.string.not_available_value);
|
||||||
mCadenceView.setText(R.string.not_available_value);
|
cadenceView.setText(R.string.not_available_value);
|
||||||
mDistanceView.setText(R.string.not_available_value);
|
distanceView.setText(R.string.not_available_value);
|
||||||
mTotalDistanceView.setText(R.string.not_available_value);
|
totalDistanceView.setText(R.string.not_available_value);
|
||||||
mGearRatioView.setText(R.string.not_available_value);
|
gearRatioView.setText(R.string.not_available_value);
|
||||||
mBatteryLevelView.setText(R.string.not_available);
|
batteryLevelView.setText(R.string.not_available);
|
||||||
|
|
||||||
setUnits();
|
setUnits();
|
||||||
}
|
}
|
||||||
@@ -107,19 +109,19 @@ public class CSCActivity extends BleProfileServiceReadyActivity<CSCService.CSCBi
|
|||||||
|
|
||||||
switch (unit) {
|
switch (unit) {
|
||||||
case SettingsFragment.SETTINGS_UNIT_M_S: // [m/s]
|
case SettingsFragment.SETTINGS_UNIT_M_S: // [m/s]
|
||||||
mSpeedUnitView.setText(R.string.csc_speed_unit_m_s);
|
speedUnitView.setText(R.string.csc_speed_unit_m_s);
|
||||||
mDistanceUnitView.setText(R.string.csc_distance_unit_m);
|
distanceUnitView.setText(R.string.csc_distance_unit_m);
|
||||||
mTotalDistanceUnitView.setText(R.string.csc_total_distance_unit_km);
|
totalDistanceUnitView.setText(R.string.csc_total_distance_unit_km);
|
||||||
break;
|
break;
|
||||||
case SettingsFragment.SETTINGS_UNIT_KM_H: // [km/h]
|
case SettingsFragment.SETTINGS_UNIT_KM_H: // [km/h]
|
||||||
mSpeedUnitView.setText(R.string.csc_speed_unit_km_h);
|
speedUnitView.setText(R.string.csc_speed_unit_km_h);
|
||||||
mDistanceUnitView.setText(R.string.csc_distance_unit_m);
|
distanceUnitView.setText(R.string.csc_distance_unit_m);
|
||||||
mTotalDistanceUnitView.setText(R.string.csc_total_distance_unit_km);
|
totalDistanceUnitView.setText(R.string.csc_total_distance_unit_km);
|
||||||
break;
|
break;
|
||||||
case SettingsFragment.SETTINGS_UNIT_MPH: // [mph]
|
case SettingsFragment.SETTINGS_UNIT_MPH: // [mph]
|
||||||
mSpeedUnitView.setText(R.string.csc_speed_unit_mph);
|
speedUnitView.setText(R.string.csc_speed_unit_mph);
|
||||||
mDistanceUnitView.setText(R.string.csc_distance_unit_yd);
|
distanceUnitView.setText(R.string.csc_distance_unit_yd);
|
||||||
mTotalDistanceUnitView.setText(R.string.csc_total_distance_unit_mile);
|
totalDistanceUnitView.setText(R.string.csc_total_distance_unit_mile);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -177,14 +179,14 @@ public class CSCActivity extends BleProfileServiceReadyActivity<CSCService.CSCBi
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) {
|
public void onServicesDiscovered(@NonNull final BluetoothDevice device, final boolean optionalServicesFound) {
|
||||||
// not used
|
// not used
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceDisconnected(final BluetoothDevice device) {
|
public void onDeviceDisconnected(@NonNull final BluetoothDevice device) {
|
||||||
super.onDeviceDisconnected(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) {
|
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
|
// pass through intended
|
||||||
case SettingsFragment.SETTINGS_UNIT_M_S:
|
case SettingsFragment.SETTINGS_UNIT_M_S:
|
||||||
if (distance < 1000) { // 1 km in m
|
if (distance < 1000) { // 1 km in m
|
||||||
mDistanceView.setText(String.format(Locale.US, "%.0f", distance));
|
distanceView.setText(String.format(Locale.US, "%.0f", distance));
|
||||||
mDistanceUnitView.setText(R.string.csc_distance_unit_m);
|
distanceUnitView.setText(R.string.csc_distance_unit_m);
|
||||||
} else {
|
} else {
|
||||||
mDistanceView.setText(String.format(Locale.US, "%.2f", distance / 1000.0f));
|
distanceView.setText(String.format(Locale.US, "%.2f", distance / 1000.0f));
|
||||||
mDistanceUnitView.setText(R.string.csc_distance_unit_km);
|
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;
|
break;
|
||||||
case SettingsFragment.SETTINGS_UNIT_MPH:
|
case SettingsFragment.SETTINGS_UNIT_MPH:
|
||||||
speed = speed * 2.2369f;
|
speed = speed * 2.2369f;
|
||||||
if (distance < 1760) { // 1 mile in yrs
|
if (distance < 1760) { // 1 mile in yrs
|
||||||
mDistanceView.setText(String.format(Locale.US, "%.0f", distance));
|
distanceView.setText(String.format(Locale.US, "%.0f", distance));
|
||||||
mDistanceUnitView.setText(R.string.csc_distance_unit_yd);
|
distanceUnitView.setText(R.string.csc_distance_unit_yd);
|
||||||
} else {
|
} else {
|
||||||
mDistanceView.setText(String.format(Locale.US, "%.2f", distance / 1760.0f));
|
distanceView.setText(String.format(Locale.US, "%.2f", distance / 1760.0f));
|
||||||
mDistanceUnitView.setText(R.string.csc_distance_unit_mile);
|
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;
|
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) {
|
private void onGearRatioUpdate(final BluetoothDevice device, final int cadence, final float ratio) {
|
||||||
mCadenceView.setText(String.format(Locale.US, "%d", cadence));
|
cadenceView.setText(String.format(Locale.US, "%d", cadence));
|
||||||
mGearRatioView.setText(String.format(Locale.US, "%.1f", ratio));
|
gearRatioView.setText(String.format(Locale.US, "%.1f", ratio));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onBatteryLevelChanged(final BluetoothDevice device, final int value) {
|
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
|
@Override
|
||||||
public void onReceive(final Context context, final Intent intent) {
|
public void onReceive(final Context context, final Intent intent) {
|
||||||
final String action = intent.getAction();
|
final String action = intent.getAction();
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ import android.bluetooth.BluetoothGattService;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
|
|
||||||
|
import androidx.annotation.FloatRange;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
@@ -43,12 +45,12 @@ import no.nordicsemi.android.nrftoolbox.parser.CSCMeasurementParser;
|
|||||||
|
|
||||||
public class CSCManager extends BatteryManager<CSCManagerCallbacks> {
|
public class CSCManager extends BatteryManager<CSCManagerCallbacks> {
|
||||||
/** Cycling Speed and Cadence service UUID. */
|
/** 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. */
|
/** Cycling Speed and Cadence Measurement characteristic UUID. */
|
||||||
private final static UUID CSC_MEASUREMENT_CHARACTERISTIC_UUID = UUID.fromString("00002A5B-0000-1000-8000-00805f9b34fb");
|
private final static UUID CSC_MEASUREMENT_CHARACTERISTIC_UUID = UUID.fromString("00002A5B-0000-1000-8000-00805f9b34fb");
|
||||||
|
|
||||||
private final SharedPreferences preferences;
|
private final SharedPreferences preferences;
|
||||||
private BluetoothGattCharacteristic mCSCMeasurementCharacteristic;
|
private BluetoothGattCharacteristic cscMeasurementCharacteristic;
|
||||||
|
|
||||||
CSCManager(final Context context) {
|
CSCManager(final Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
@@ -58,21 +60,21 @@ public class CSCManager extends BatteryManager<CSCManagerCallbacks> {
|
|||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
protected BatteryManagerGattCallback getGattCallback() {
|
protected BatteryManagerGattCallback getGattCallback() {
|
||||||
return mGattCallback;
|
return gattCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BluetoothGatt callbacks for connection/disconnection, service discovery,
|
* BluetoothGatt callbacks for connection/disconnection, service discovery,
|
||||||
* receiving indication, etc.
|
* receiving indication, etc.
|
||||||
*/
|
*/
|
||||||
private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() {
|
private final BatteryManagerGattCallback gattCallback = new BatteryManagerGattCallback() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initialize() {
|
protected void initialize() {
|
||||||
super.initialize();
|
super.initialize();
|
||||||
|
|
||||||
// CSC characteristic is required
|
// CSC characteristic is required
|
||||||
setNotificationCallback(mCSCMeasurementCharacteristic)
|
setNotificationCallback(cscMeasurementCharacteristic)
|
||||||
.with(new CyclingSpeedAndCadenceMeasurementDataCallback() {
|
.with(new CyclingSpeedAndCadenceMeasurementDataCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onDataReceived(@NonNull final BluetoothDevice device, final @NonNull Data data) {
|
public void onDataReceived(@NonNull final BluetoothDevice device, final @NonNull Data data) {
|
||||||
@@ -90,38 +92,41 @@ public class CSCManager extends BatteryManager<CSCManagerCallbacks> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDistanceChanged(@NonNull final BluetoothDevice device,
|
public void onDistanceChanged(@NonNull final BluetoothDevice device,
|
||||||
final float totalDistance, final float distance, final float speed) {
|
@FloatRange(from = 0) final float totalDistance,
|
||||||
mCallbacks.onDistanceChanged(device, totalDistance, distance, speed);
|
@FloatRange(from = 0) final float distance,
|
||||||
|
@FloatRange(from = 0) final float speed) {
|
||||||
|
callbacks.onDistanceChanged(device, totalDistance, distance, speed);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCrankDataChanged(@NonNull final BluetoothDevice device,
|
public void onCrankDataChanged(@NonNull final BluetoothDevice device,
|
||||||
final float crankCadence, final float gearRatio) {
|
@FloatRange(from = 0) final float crankCadence,
|
||||||
mCallbacks.onCrankDataChanged(device, crankCadence, gearRatio);
|
final float gearRatio) {
|
||||||
|
callbacks.onCrankDataChanged(device, crankCadence, gearRatio);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onInvalidDataReceived(@NonNull final BluetoothDevice device,
|
public void onInvalidDataReceived(@NonNull final BluetoothDevice device,
|
||||||
final @NonNull Data data) {
|
@NonNull final Data data) {
|
||||||
log(Log.WARN, "Invalid CSC Measurement data received: " + data);
|
log(Log.WARN, "Invalid CSC Measurement data received: " + data);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
enableNotifications(mCSCMeasurementCharacteristic).enqueue();
|
enableNotifications(cscMeasurementCharacteristic).enqueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) {
|
public boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) {
|
||||||
final BluetoothGattService service = gatt.getService(CYCLING_SPEED_AND_CADENCE_SERVICE_UUID);
|
final BluetoothGattService service = gatt.getService(CYCLING_SPEED_AND_CADENCE_SERVICE_UUID);
|
||||||
if (service != null) {
|
if (service != null) {
|
||||||
mCSCMeasurementCharacteristic = service.getCharacteristic(CSC_MEASUREMENT_CHARACTERISTIC_UUID);
|
cscMeasurementCharacteristic = service.getCharacteristic(CSC_MEASUREMENT_CHARACTERISTIC_UUID);
|
||||||
}
|
}
|
||||||
return mCSCMeasurementCharacteristic != null;
|
return cscMeasurementCharacteristic != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDeviceDisconnected() {
|
protected void onDeviceDisconnected() {
|
||||||
super.onDeviceDisconnected();
|
super.onDeviceDisconnected();
|
||||||
mCSCMeasurementCharacteristic = null;
|
cscMeasurementCharacteristic = null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,8 +73,8 @@ public class CSCService extends BleProfileService implements CSCManagerCallbacks
|
|||||||
private final static int OPEN_ACTIVITY_REQ = 0;
|
private final static int OPEN_ACTIVITY_REQ = 0;
|
||||||
private final static int DISCONNECT_REQ = 1;
|
private final static int DISCONNECT_REQ = 1;
|
||||||
|
|
||||||
private final LocalBinder mBinder = new CSCBinder();
|
private final LocalBinder binder = new CSCBinder();
|
||||||
private CSCManager mManager;
|
private CSCManager manager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This local binder is an interface for the bonded activity to operate with the RSC sensor
|
* 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
|
@Override
|
||||||
protected LocalBinder getBinder() {
|
protected LocalBinder getBinder() {
|
||||||
return mBinder;
|
return binder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected LoggableBleManager<CSCManagerCallbacks> initializeManager() {
|
protected LoggableBleManager<CSCManagerCallbacks> initializeManager() {
|
||||||
return mManager = new CSCManager(this);
|
return manager = new CSCManager(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -99,14 +99,14 @@ public class CSCService extends BleProfileService implements CSCManagerCallbacks
|
|||||||
|
|
||||||
final IntentFilter filter = new IntentFilter();
|
final IntentFilter filter = new IntentFilter();
|
||||||
filter.addAction(ACTION_DISCONNECT);
|
filter.addAction(ACTION_DISCONNECT);
|
||||||
registerReceiver(mDisconnectActionBroadcastReceiver, filter);
|
registerReceiver(disconnectActionBroadcastReceiver, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
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
|
// when user has disconnected from the sensor, we have to cancel the notification that we've created some milliseconds before using unbindService
|
||||||
cancelNotification();
|
cancelNotification();
|
||||||
unregisterReceiver(mDisconnectActionBroadcastReceiver);
|
unregisterReceiver(disconnectActionBroadcastReceiver);
|
||||||
|
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
}
|
}
|
||||||
@@ -118,7 +118,7 @@ public class CSCService extends BleProfileService implements CSCManagerCallbacks
|
|||||||
if (isConnected()) {
|
if (isConnected()) {
|
||||||
// This method will read the Battery Level value, if possible and then try to enable battery notifications (if it has NOTIFY property).
|
// 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.
|
// 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.
|
// 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.
|
// But we will still be receiving other values, if enabled.
|
||||||
if (isConnected())
|
if (isConnected())
|
||||||
mManager.disableBatteryLevelCharacteristicNotifications();
|
manager.disableBatteryLevelCharacteristicNotifications();
|
||||||
startForegroundService();
|
startForegroundService();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,6 +193,7 @@ public class CSCService extends BleProfileService implements CSCManagerCallbacks
|
|||||||
* f.e. <code><string name="name">%s is connected</string></code>
|
* f.e. <code><string name="name">%s is connected</string></code>
|
||||||
* @param defaults
|
* @param defaults
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("SameParameterValue")
|
||||||
private Notification createNotification(final int messageResId, final int defaults) {
|
private Notification createNotification(final int messageResId, final int defaults) {
|
||||||
final Intent parentIntent = new Intent(this, FeaturesActivity.class);
|
final Intent parentIntent = new Intent(this, FeaturesActivity.class);
|
||||||
parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
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.
|
* 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
|
@Override
|
||||||
public void onReceive(final Context context, final Intent intent) {
|
public void onReceive(final Context context, final Intent intent) {
|
||||||
Logger.i(getLogSession(), "[Notification] Disconnect action pressed");
|
Logger.i(getLogSession(), "[Notification] Disconnect action pressed");
|
||||||
|
|||||||
@@ -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_FILE_REQ = 1;
|
||||||
private static final int SELECT_INIT_FILE_REQ = 2;
|
private static final int SELECT_INIT_FILE_REQ = 2;
|
||||||
|
|
||||||
private TextView mDeviceNameView;
|
private TextView deviceNameView;
|
||||||
private TextView mFileNameView;
|
private TextView fileNameView;
|
||||||
private TextView mFileTypeView;
|
private TextView fileTypeView;
|
||||||
private TextView mFileScopeView;
|
private TextView fileScopeView;
|
||||||
private TextView mFileSizeView;
|
private TextView fileSizeView;
|
||||||
private TextView mFileStatusView;
|
private TextView fileStatusView;
|
||||||
private TextView mTextPercentage;
|
private TextView textPercentage;
|
||||||
private TextView mTextUploading;
|
private TextView textUploading;
|
||||||
private ProgressBar mProgressBar;
|
private ProgressBar progressBar;
|
||||||
|
|
||||||
private Button mSelectFileButton, mUploadButton, mConnectButton;
|
private Button selectFileButton, uploadButton, connectButton;
|
||||||
|
|
||||||
private BluetoothDevice mSelectedDevice;
|
private BluetoothDevice selectedDevice;
|
||||||
private String mFilePath;
|
private String filePath;
|
||||||
private Uri mFileStreamUri;
|
private Uri fileStreamUri;
|
||||||
private String mInitFilePath;
|
private String initFilePath;
|
||||||
private Uri mInitFileStreamUri;
|
private Uri initFileStreamUri;
|
||||||
private int mFileType;
|
private int fileType;
|
||||||
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 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 mScope;
|
private Integer scope;
|
||||||
private boolean mStatusOk;
|
private boolean statusOk;
|
||||||
/** Flag set to true in {@link #onRestart()} and to false in {@link #onPause()}. */
|
/** Flag set to true in {@link #onRestart()} and to false in {@link #onPause()}. */
|
||||||
private boolean mResumed;
|
private boolean resumed;
|
||||||
/** Flag set to true if DFU operation was completed while {@link #mResumed} was false. */
|
/** Flag set to true if DFU operation was completed while {@link #resumed} was false. */
|
||||||
private boolean mDfuCompleted;
|
private boolean dfuCompleted;
|
||||||
/** The error message received from DFU service while {@link #mResumed} was false. */
|
/** The error message received from DFU service while {@link #resumed} was false. */
|
||||||
private String mDfuError;
|
private String dfuError;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The progress listener receives events from the DFU Service.
|
* 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
|
* 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).
|
* 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
|
@Override
|
||||||
public void onDeviceConnecting(final String deviceAddress) {
|
public void onDeviceConnecting(@NonNull final String deviceAddress) {
|
||||||
mProgressBar.setIndeterminate(true);
|
progressBar.setIndeterminate(true);
|
||||||
mTextPercentage.setText(R.string.dfu_status_connecting);
|
textPercentage.setText(R.string.dfu_status_connecting);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDfuProcessStarting(final String deviceAddress) {
|
public void onDfuProcessStarting(@NonNull final String deviceAddress) {
|
||||||
mProgressBar.setIndeterminate(true);
|
progressBar.setIndeterminate(true);
|
||||||
mTextPercentage.setText(R.string.dfu_status_starting);
|
textPercentage.setText(R.string.dfu_status_starting);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnablingDfuMode(final String deviceAddress) {
|
public void onEnablingDfuMode(@NonNull final String deviceAddress) {
|
||||||
mProgressBar.setIndeterminate(true);
|
progressBar.setIndeterminate(true);
|
||||||
mTextPercentage.setText(R.string.dfu_status_switching_to_dfu);
|
textPercentage.setText(R.string.dfu_status_switching_to_dfu);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFirmwareValidating(final String deviceAddress) {
|
public void onFirmwareValidating(@NonNull final String deviceAddress) {
|
||||||
mProgressBar.setIndeterminate(true);
|
progressBar.setIndeterminate(true);
|
||||||
mTextPercentage.setText(R.string.dfu_status_validating);
|
textPercentage.setText(R.string.dfu_status_validating);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceDisconnecting(final String deviceAddress) {
|
public void onDeviceDisconnecting(@NonNull final String deviceAddress) {
|
||||||
mProgressBar.setIndeterminate(true);
|
progressBar.setIndeterminate(true);
|
||||||
mTextPercentage.setText(R.string.dfu_status_disconnecting);
|
textPercentage.setText(R.string.dfu_status_disconnecting);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDfuCompleted(final String deviceAddress) {
|
public void onDfuCompleted(@NonNull final String deviceAddress) {
|
||||||
mTextPercentage.setText(R.string.dfu_status_completed);
|
textPercentage.setText(R.string.dfu_status_completed);
|
||||||
if (mResumed) {
|
if (resumed) {
|
||||||
// let's wait a bit until we cancel the notification. When canceled immediately it will be recreated by service again.
|
// let's wait a bit until we cancel the notification. When canceled immediately it will be recreated by service again.
|
||||||
new Handler().postDelayed(() -> {
|
new Handler().postDelayed(() -> {
|
||||||
onTransferCompleted();
|
onTransferCompleted();
|
||||||
@@ -191,13 +191,13 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
|
|||||||
}, 200);
|
}, 200);
|
||||||
} else {
|
} else {
|
||||||
// Save that the DFU process has finished
|
// Save that the DFU process has finished
|
||||||
mDfuCompleted = true;
|
dfuCompleted = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDfuAborted(final String deviceAddress) {
|
public void onDfuAborted(@NonNull final String deviceAddress) {
|
||||||
mTextPercentage.setText(R.string.dfu_status_aborted);
|
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.
|
// let's wait a bit until we cancel the notification. When canceled immediately it will be recreated by service again.
|
||||||
new Handler().postDelayed(() -> {
|
new Handler().postDelayed(() -> {
|
||||||
onUploadCanceled();
|
onUploadCanceled();
|
||||||
@@ -209,19 +209,21 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onProgressChanged(final String deviceAddress, final int percent, final float speed, final float avgSpeed, final int currentPart, final int partsTotal) {
|
public void onProgressChanged(@NonNull final String deviceAddress, final int percent,
|
||||||
mProgressBar.setIndeterminate(false);
|
final float speed, final float avgSpeed,
|
||||||
mProgressBar.setProgress(percent);
|
final int currentPart, final int partsTotal) {
|
||||||
mTextPercentage.setText(getString(R.string.dfu_uploading_percentage, percent));
|
progressBar.setIndeterminate(false);
|
||||||
|
progressBar.setProgress(percent);
|
||||||
|
textPercentage.setText(getString(R.string.dfu_uploading_percentage, percent));
|
||||||
if (partsTotal > 1)
|
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
|
else
|
||||||
mTextUploading.setText(R.string.dfu_status_uploading);
|
textUploading.setText(R.string.dfu_status_uploading);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onError(final String deviceAddress, final int error, final int errorType, final String message) {
|
public void onError(@NonNull final String deviceAddress, final int error, final int errorType, final String message) {
|
||||||
if (mResumed) {
|
if (resumed) {
|
||||||
showErrorMessage(message);
|
showErrorMessage(message);
|
||||||
|
|
||||||
// We have to wait a bit before canceling notification. This is called before DfuService creates the last notification.
|
// 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);
|
manager.cancel(DfuService.NOTIFICATION_ID);
|
||||||
}, 200);
|
}, 200);
|
||||||
} else {
|
} else {
|
||||||
mDfuError = message;
|
dfuError = message;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -257,45 +259,45 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
|
|||||||
}
|
}
|
||||||
|
|
||||||
// restore saved state
|
// restore saved state
|
||||||
mFileType = DfuService.TYPE_AUTO; // Default
|
fileType = DfuService.TYPE_AUTO; // Default
|
||||||
if (savedInstanceState != null) {
|
if (savedInstanceState != null) {
|
||||||
mFileType = savedInstanceState.getInt(DATA_FILE_TYPE);
|
fileType = savedInstanceState.getInt(DATA_FILE_TYPE);
|
||||||
mFileTypeTmp = savedInstanceState.getInt(DATA_FILE_TYPE_TMP);
|
fileTypeTmp = savedInstanceState.getInt(DATA_FILE_TYPE_TMP);
|
||||||
mFilePath = savedInstanceState.getString(DATA_FILE_PATH);
|
filePath = savedInstanceState.getString(DATA_FILE_PATH);
|
||||||
mFileStreamUri = savedInstanceState.getParcelable(DATA_FILE_STREAM);
|
fileStreamUri = savedInstanceState.getParcelable(DATA_FILE_STREAM);
|
||||||
mInitFilePath = savedInstanceState.getString(DATA_INIT_FILE_PATH);
|
initFilePath = savedInstanceState.getString(DATA_INIT_FILE_PATH);
|
||||||
mInitFileStreamUri = savedInstanceState.getParcelable(DATA_INIT_FILE_STREAM);
|
initFileStreamUri = savedInstanceState.getParcelable(DATA_INIT_FILE_STREAM);
|
||||||
mSelectedDevice = savedInstanceState.getParcelable(DATA_DEVICE);
|
selectedDevice = savedInstanceState.getParcelable(DATA_DEVICE);
|
||||||
mStatusOk = mStatusOk || savedInstanceState.getBoolean(DATA_STATUS);
|
statusOk = statusOk || savedInstanceState.getBoolean(DATA_STATUS);
|
||||||
mScope = savedInstanceState.containsKey(DATA_SCOPE) ? savedInstanceState.getInt(DATA_SCOPE) : null;
|
scope = savedInstanceState.containsKey(DATA_SCOPE) ? savedInstanceState.getInt(DATA_SCOPE) : null;
|
||||||
mUploadButton.setEnabled(mSelectedDevice != null && mStatusOk);
|
uploadButton.setEnabled(selectedDevice != null && statusOk);
|
||||||
mDfuCompleted = savedInstanceState.getBoolean(DATA_DFU_COMPLETED);
|
dfuCompleted = savedInstanceState.getBoolean(DATA_DFU_COMPLETED);
|
||||||
mDfuError = savedInstanceState.getString(DATA_DFU_ERROR);
|
dfuError = savedInstanceState.getString(DATA_DFU_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
DfuServiceListenerHelper.registerProgressListener(this, mDfuProgressListener);
|
DfuServiceListenerHelper.registerProgressListener(this, dfuProgressListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
DfuServiceListenerHelper.unregisterProgressListener(this, mDfuProgressListener);
|
DfuServiceListenerHelper.unregisterProgressListener(this, dfuProgressListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onSaveInstanceState(final Bundle outState) {
|
protected void onSaveInstanceState(@NonNull final Bundle outState) {
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
outState.putInt(DATA_FILE_TYPE, mFileType);
|
outState.putInt(DATA_FILE_TYPE, fileType);
|
||||||
outState.putInt(DATA_FILE_TYPE_TMP, mFileTypeTmp);
|
outState.putInt(DATA_FILE_TYPE_TMP, fileTypeTmp);
|
||||||
outState.putString(DATA_FILE_PATH, mFilePath);
|
outState.putString(DATA_FILE_PATH, filePath);
|
||||||
outState.putParcelable(DATA_FILE_STREAM, mFileStreamUri);
|
outState.putParcelable(DATA_FILE_STREAM, fileStreamUri);
|
||||||
outState.putString(DATA_INIT_FILE_PATH, mInitFilePath);
|
outState.putString(DATA_INIT_FILE_PATH, initFilePath);
|
||||||
outState.putParcelable(DATA_INIT_FILE_STREAM, mInitFileStreamUri);
|
outState.putParcelable(DATA_INIT_FILE_STREAM, initFileStreamUri);
|
||||||
outState.putParcelable(DATA_DEVICE, mSelectedDevice);
|
outState.putParcelable(DATA_DEVICE, selectedDevice);
|
||||||
outState.putBoolean(DATA_STATUS, mStatusOk);
|
outState.putBoolean(DATA_STATUS, statusOk);
|
||||||
if (mScope != null) outState.putInt(DATA_SCOPE, mScope);
|
if (scope != null) outState.putInt(DATA_SCOPE, scope);
|
||||||
outState.putBoolean(DATA_DFU_COMPLETED, mDfuCompleted);
|
outState.putBoolean(DATA_DFU_COMPLETED, dfuCompleted);
|
||||||
outState.putString(DATA_DFU_ERROR, mDfuError);
|
outState.putString(DATA_DFU_ERROR, dfuError);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setGUI() {
|
private void setGUI() {
|
||||||
@@ -303,29 +305,29 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
|
|||||||
setSupportActionBar(toolbar);
|
setSupportActionBar(toolbar);
|
||||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||||
|
|
||||||
mDeviceNameView = findViewById(R.id.device_name);
|
deviceNameView = findViewById(R.id.device_name);
|
||||||
mFileNameView = findViewById(R.id.file_name);
|
fileNameView = findViewById(R.id.file_name);
|
||||||
mFileTypeView = findViewById(R.id.file_type);
|
fileTypeView = findViewById(R.id.file_type);
|
||||||
mFileScopeView = findViewById(R.id.file_scope);
|
fileScopeView = findViewById(R.id.file_scope);
|
||||||
mFileSizeView = findViewById(R.id.file_size);
|
fileSizeView = findViewById(R.id.file_size);
|
||||||
mFileStatusView = findViewById(R.id.file_status);
|
fileStatusView = findViewById(R.id.file_status);
|
||||||
mSelectFileButton = findViewById(R.id.action_select_file);
|
selectFileButton = findViewById(R.id.action_select_file);
|
||||||
mUploadButton = findViewById(R.id.action_upload);
|
uploadButton = findViewById(R.id.action_upload);
|
||||||
mConnectButton = findViewById(R.id.action_connect);
|
connectButton = findViewById(R.id.action_connect);
|
||||||
mTextPercentage = findViewById(R.id.textviewProgress);
|
textPercentage = findViewById(R.id.textviewProgress);
|
||||||
mTextUploading = findViewById(R.id.textviewUploading);
|
textUploading = findViewById(R.id.textviewUploading);
|
||||||
mProgressBar = findViewById(R.id.progressbar_file);
|
progressBar = findViewById(R.id.progressbar_file);
|
||||||
|
|
||||||
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
|
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
if (isDfuServiceRunning()) {
|
if (isDfuServiceRunning()) {
|
||||||
// Restore image file information
|
// Restore image file information
|
||||||
mDeviceNameView.setText(preferences.getString(PREFS_DEVICE_NAME, ""));
|
deviceNameView.setText(preferences.getString(PREFS_DEVICE_NAME, ""));
|
||||||
mFileNameView.setText(preferences.getString(PREFS_FILE_NAME, ""));
|
fileNameView.setText(preferences.getString(PREFS_FILE_NAME, ""));
|
||||||
mFileTypeView.setText(preferences.getString(PREFS_FILE_TYPE, ""));
|
fileTypeView.setText(preferences.getString(PREFS_FILE_TYPE, ""));
|
||||||
mFileScopeView.setText(preferences.getString(PREFS_FILE_SCOPE, ""));
|
fileScopeView.setText(preferences.getString(PREFS_FILE_SCOPE, ""));
|
||||||
mFileSizeView.setText(preferences.getString(PREFS_FILE_SIZE, ""));
|
fileSizeView.setText(preferences.getString(PREFS_FILE_SIZE, ""));
|
||||||
mFileStatusView.setText(R.string.dfu_file_status_ok);
|
fileStatusView.setText(R.string.dfu_file_status_ok);
|
||||||
mStatusOk = true;
|
statusOk = true;
|
||||||
showProgressBar();
|
showProgressBar();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -333,24 +335,24 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
|
|||||||
@Override
|
@Override
|
||||||
protected void onResume() {
|
protected void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
mResumed = true;
|
resumed = true;
|
||||||
if (mDfuCompleted)
|
if (dfuCompleted)
|
||||||
onTransferCompleted();
|
onTransferCompleted();
|
||||||
if (mDfuError != null)
|
if (dfuError != null)
|
||||||
showErrorMessage(mDfuError);
|
showErrorMessage(dfuError);
|
||||||
if (mDfuCompleted || mDfuError != null) {
|
if (dfuCompleted || dfuError != null) {
|
||||||
// if this activity is still open and upload process was completed, cancel the notification
|
// if this activity is still open and upload process was completed, cancel the notification
|
||||||
final NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
final NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
manager.cancel(DfuService.NOTIFICATION_ID);
|
manager.cancel(DfuService.NOTIFICATION_ID);
|
||||||
mDfuCompleted = false;
|
dfuCompleted = false;
|
||||||
mDfuError = null;
|
dfuError = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPause() {
|
protected void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
mResumed = false;
|
resumed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -429,9 +431,9 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
|
|||||||
switch (requestCode) {
|
switch (requestCode) {
|
||||||
case SELECT_FILE_REQ: {
|
case SELECT_FILE_REQ: {
|
||||||
// clear previous data
|
// clear previous data
|
||||||
mFileType = mFileTypeTmp;
|
fileType = fileTypeTmp;
|
||||||
mFilePath = null;
|
filePath = null;
|
||||||
mFileStreamUri = null;
|
fileStreamUri = null;
|
||||||
|
|
||||||
// and read new one
|
// and read new one
|
||||||
final Uri uri = data.getData();
|
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
|
// the direct path to the file has been returned
|
||||||
final String path = uri.getPath();
|
final String path = uri.getPath();
|
||||||
final File file = new File(path);
|
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")) {
|
} else if (uri.getScheme().equals("content")) {
|
||||||
// an Uri has been returned
|
// an Uri has been returned
|
||||||
mFileStreamUri = uri;
|
fileStreamUri = uri;
|
||||||
// if application returned Uri for streaming, let's us it. Does it works?
|
// 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?
|
// 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();
|
final Bundle extras = data.getExtras();
|
||||||
if (extras != null && extras.containsKey(Intent.EXTRA_STREAM))
|
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
|
// file name and size must be obtained from Content Provider
|
||||||
final Bundle bundle = new Bundle();
|
final Bundle bundle = new Bundle();
|
||||||
@@ -463,8 +465,8 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SELECT_INIT_FILE_REQ: {
|
case SELECT_INIT_FILE_REQ: {
|
||||||
mInitFilePath = null;
|
initFilePath = null;
|
||||||
mInitFileStreamUri = null;
|
initFileStreamUri = null;
|
||||||
|
|
||||||
// and read new one
|
// and read new one
|
||||||
final Uri uri = data.getData();
|
final Uri uri = data.getData();
|
||||||
@@ -474,17 +476,17 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
|
|||||||
*/
|
*/
|
||||||
if (uri.getScheme().equals("file")) {
|
if (uri.getScheme().equals("file")) {
|
||||||
// the direct path to the file has been returned
|
// the direct path to the file has been returned
|
||||||
mInitFilePath = uri.getPath();
|
initFilePath = uri.getPath();
|
||||||
mFileStatusView.setText(R.string.dfu_file_status_ok_with_init);
|
fileStatusView.setText(R.string.dfu_file_status_ok_with_init);
|
||||||
} else if (uri.getScheme().equals("content")) {
|
} else if (uri.getScheme().equals("content")) {
|
||||||
// an Uri has been returned
|
// an Uri has been returned
|
||||||
mInitFileStreamUri = uri;
|
initFileStreamUri = uri;
|
||||||
// if application returned Uri for streaming, let's us it. Does it works?
|
// 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?
|
// 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();
|
final Bundle extras = data.getExtras();
|
||||||
if (extras != null && extras.containsKey(Intent.EXTRA_STREAM))
|
if (extras != null && extras.containsKey(Intent.EXTRA_STREAM))
|
||||||
mInitFileStreamUri = extras.getParcelable(Intent.EXTRA_STREAM);
|
initFileStreamUri = extras.getParcelable(Intent.EXTRA_STREAM);
|
||||||
mFileStatusView.setText(R.string.dfu_file_status_ok_with_init);
|
fileStatusView.setText(R.string.dfu_file_status_ok_with_init);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -506,12 +508,12 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoaderReset(final Loader<Cursor> loader) {
|
public void onLoaderReset(final Loader<Cursor> loader) {
|
||||||
mFileNameView.setText(null);
|
fileNameView.setText(null);
|
||||||
mFileTypeView.setText(null);
|
fileTypeView.setText(null);
|
||||||
mFileSizeView.setText(null);
|
fileSizeView.setText(null);
|
||||||
mFilePath = null;
|
filePath = null;
|
||||||
mFileStreamUri = null;
|
fileStreamUri = null;
|
||||||
mStatusOk = false;
|
statusOk = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -527,17 +529,17 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
|
|||||||
if (dataIndex != -1)
|
if (dataIndex != -1)
|
||||||
filePath = data.getString(dataIndex /* 2 DATA */);
|
filePath = data.getString(dataIndex /* 2 DATA */);
|
||||||
if (!TextUtils.isEmpty(filePath))
|
if (!TextUtils.isEmpty(filePath))
|
||||||
mFilePath = filePath;
|
this.filePath = filePath;
|
||||||
|
|
||||||
updateFileInfo(fileName, fileSize, mFileType);
|
updateFileInfo(fileName, fileSize, fileType);
|
||||||
} else {
|
} else {
|
||||||
mFileNameView.setText(null);
|
fileNameView.setText(null);
|
||||||
mFileTypeView.setText(null);
|
fileTypeView.setText(null);
|
||||||
mFileSizeView.setText(null);
|
fileSizeView.setText(null);
|
||||||
mFilePath = null;
|
filePath = null;
|
||||||
mFileStreamUri = null;
|
fileStreamUri = null;
|
||||||
mFileStatusView.setText(R.string.dfu_file_status_error);
|
fileStatusView.setText(R.string.dfu_file_status_error);
|
||||||
mStatusOk = false;
|
statusOk = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -548,37 +550,37 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
|
|||||||
* @param fileSize file length
|
* @param fileSize file length
|
||||||
*/
|
*/
|
||||||
private void updateFileInfo(final String fileName, final long fileSize, final int fileType) {
|
private void updateFileInfo(final String fileName, final long fileSize, final int fileType) {
|
||||||
mFileNameView.setText(fileName);
|
fileNameView.setText(fileName);
|
||||||
switch (fileType) {
|
switch (fileType) {
|
||||||
case DfuService.TYPE_AUTO:
|
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;
|
break;
|
||||||
case DfuService.TYPE_SOFT_DEVICE:
|
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;
|
break;
|
||||||
case DfuService.TYPE_BOOTLOADER:
|
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;
|
break;
|
||||||
case DfuService.TYPE_APPLICATION:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
mFileSizeView.setText(getString(R.string.dfu_file_size_text, fileSize));
|
fileSizeView.setText(getString(R.string.dfu_file_size_text, fileSize));
|
||||||
mFileScopeView.setText(getString(R.string.not_available));
|
fileScopeView.setText(getString(R.string.not_available));
|
||||||
final String extension = mFileType == DfuService.TYPE_AUTO ? "(?i)ZIP" : "(?i)HEX|BIN"; // (?i) = case insensitive
|
final String extension = this.fileType == DfuService.TYPE_AUTO ? "(?i)ZIP" : "(?i)HEX|BIN"; // (?i) = case insensitive
|
||||||
final boolean statusOk = mStatusOk = MimeTypeMap.getFileExtensionFromUrl(fileName).matches(extension);
|
final boolean statusOk = this.statusOk = MimeTypeMap.getFileExtensionFromUrl(fileName).matches(extension);
|
||||||
mFileStatusView.setText(statusOk ? R.string.dfu_file_status_ok : R.string.dfu_file_status_invalid);
|
fileStatusView.setText(statusOk ? R.string.dfu_file_status_ok : R.string.dfu_file_status_invalid);
|
||||||
mUploadButton.setEnabled(mSelectedDevice != null && statusOk);
|
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.
|
// 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 (statusOk) {
|
||||||
if (fileType != DfuService.TYPE_AUTO) {
|
if (fileType != DfuService.TYPE_AUTO) {
|
||||||
mScope = null;
|
scope = null;
|
||||||
mFileScopeView.setText(getString(R.string.not_available));
|
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)
|
new AlertDialog.Builder(this).setTitle(R.string.dfu_file_init_title).setMessage(R.string.dfu_file_init_message)
|
||||||
.setNegativeButton(R.string.no, (dialog, which) -> {
|
.setNegativeButton(R.string.no, (dialog, which) -> {
|
||||||
mInitFilePath = null;
|
initFilePath = null;
|
||||||
mInitFileStreamUri = null;
|
initFileStreamUri = null;
|
||||||
}).setPositiveButton(R.string.yes, (dialog, which) -> {
|
}).setPositiveButton(R.string.yes, (dialog, which) -> {
|
||||||
final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||||
intent.setType(DfuService.MIME_TYPE_OCTET_STREAM);
|
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) -> {
|
.setSingleChoiceItems(R.array.dfu_file_scope, 0, (dialog, which) -> {
|
||||||
switch (which) {
|
switch (which) {
|
||||||
case 0:
|
case 0:
|
||||||
mScope = null;
|
scope = null;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
mScope = DfuServiceInitiator.SCOPE_SYSTEM_COMPONENTS;
|
scope = DfuServiceInitiator.SCOPE_SYSTEM_COMPONENTS;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
mScope = DfuServiceInitiator.SCOPE_APPLICATION;
|
scope = DfuServiceInitiator.SCOPE_APPLICATION;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}).setPositiveButton(R.string.ok, (dialogInterface, i) -> {
|
}).setPositiveButton(R.string.ok, (dialogInterface, i) -> {
|
||||||
int index;
|
int index;
|
||||||
if (mScope == null) {
|
if (scope == null) {
|
||||||
index = 0;
|
index = 0;
|
||||||
} else if (mScope == DfuServiceInitiator.SCOPE_SYSTEM_COMPONENTS) {
|
} else if (scope == DfuServiceInitiator.SCOPE_SYSTEM_COMPONENTS) {
|
||||||
index = 1;
|
index = 1;
|
||||||
} else {
|
} else {
|
||||||
index = 2;
|
index = 2;
|
||||||
}
|
}
|
||||||
mFileScopeView.setText(getResources().getStringArray(R.array.dfu_file_scope)[index]);
|
fileScopeView.setText(getResources().getStringArray(R.array.dfu_file_scope)[index]);
|
||||||
}).show();
|
}).show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -630,9 +632,9 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
|
|||||||
* @param view a button that was pressed
|
* @param view a button that was pressed
|
||||||
*/
|
*/
|
||||||
public void onSelectFileClicked(final View view) {
|
public void onSelectFileClicked(final View view) {
|
||||||
mFileTypeTmp = mFileType;
|
fileTypeTmp = fileType;
|
||||||
int index = 0;
|
int index = 0;
|
||||||
switch (mFileType) {
|
switch (fileType) {
|
||||||
case DfuService.TYPE_AUTO:
|
case DfuService.TYPE_AUTO:
|
||||||
index = 0;
|
index = 0;
|
||||||
break;
|
break;
|
||||||
@@ -651,16 +653,16 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
|
|||||||
.setSingleChoiceItems(R.array.dfu_file_type, index, (dialog, which) -> {
|
.setSingleChoiceItems(R.array.dfu_file_type, index, (dialog, which) -> {
|
||||||
switch (which) {
|
switch (which) {
|
||||||
case 0:
|
case 0:
|
||||||
mFileTypeTmp = DfuService.TYPE_AUTO;
|
fileTypeTmp = DfuService.TYPE_AUTO;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
mFileTypeTmp = DfuService.TYPE_SOFT_DEVICE;
|
fileTypeTmp = DfuService.TYPE_SOFT_DEVICE;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
mFileTypeTmp = DfuService.TYPE_BOOTLOADER;
|
fileTypeTmp = DfuService.TYPE_BOOTLOADER;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
mFileTypeTmp = DfuService.TYPE_APPLICATION;
|
fileTypeTmp = DfuService.TYPE_APPLICATION;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}).setPositiveButton(R.string.ok, (dialog, which) -> openFileChooser()).setNeutralButton(R.string.dfu_file_info, (dialog, which) -> {
|
}).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() {
|
private void openFileChooser() {
|
||||||
final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
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);
|
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||||
if (intent.resolveActivity(getPackageManager()) != null) {
|
if (intent.resolveActivity(getPackageManager()) != null) {
|
||||||
// file browser has been found on the device
|
// 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)
|
// 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();
|
Toast.makeText(this, R.string.dfu_file_status_invalid_message, Toast.LENGTH_LONG).show();
|
||||||
return;
|
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
|
// Save current state in order to restore it if user quit the Activity
|
||||||
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
|
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
final SharedPreferences.Editor editor = preferences.edit();
|
final SharedPreferences.Editor editor = preferences.edit();
|
||||||
editor.putString(PREFS_DEVICE_NAME, mSelectedDevice.getName());
|
editor.putString(PREFS_DEVICE_NAME, selectedDevice.getName());
|
||||||
editor.putString(PREFS_FILE_NAME, mFileNameView.getText().toString());
|
editor.putString(PREFS_FILE_NAME, fileNameView.getText().toString());
|
||||||
editor.putString(PREFS_FILE_TYPE, mFileTypeView.getText().toString());
|
editor.putString(PREFS_FILE_TYPE, fileTypeView.getText().toString());
|
||||||
editor.putString(PREFS_FILE_SCOPE, mFileScopeView.getText().toString());
|
editor.putString(PREFS_FILE_SCOPE, fileScopeView.getText().toString());
|
||||||
editor.putString(PREFS_FILE_SIZE, mFileSizeView.getText().toString());
|
editor.putString(PREFS_FILE_SIZE, fileSizeView.getText().toString());
|
||||||
editor.apply();
|
editor.apply();
|
||||||
|
|
||||||
showProgressBar();
|
showProgressBar();
|
||||||
@@ -733,19 +735,19 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
|
|||||||
numberOfPackets = DfuServiceInitiator.DEFAULT_PRN_VALUE;
|
numberOfPackets = DfuServiceInitiator.DEFAULT_PRN_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
final DfuServiceInitiator starter = new DfuServiceInitiator(mSelectedDevice.getAddress())
|
final DfuServiceInitiator starter = new DfuServiceInitiator(selectedDevice.getAddress())
|
||||||
.setDeviceName(mSelectedDevice.getName())
|
.setDeviceName(selectedDevice.getName())
|
||||||
.setKeepBond(keepBond)
|
.setKeepBond(keepBond)
|
||||||
.setForceDfu(forceDfu)
|
.setForceDfu(forceDfu)
|
||||||
.setPacketsReceiptNotificationsEnabled(enablePRNs)
|
.setPacketsReceiptNotificationsEnabled(enablePRNs)
|
||||||
.setPacketsReceiptNotificationsValue(numberOfPackets)
|
.setPacketsReceiptNotificationsValue(numberOfPackets)
|
||||||
.setUnsafeExperimentalButtonlessServiceInSecureDfuEnabled(true);
|
.setUnsafeExperimentalButtonlessServiceInSecureDfuEnabled(true);
|
||||||
if (mFileType == DfuService.TYPE_AUTO) {
|
if (fileType == DfuService.TYPE_AUTO) {
|
||||||
starter.setZip(mFileStreamUri, mFilePath);
|
starter.setZip(fileStreamUri, filePath);
|
||||||
if (mScope != null)
|
if (scope != null)
|
||||||
starter.setScope(mScope);
|
starter.setScope(scope);
|
||||||
} else {
|
} else {
|
||||||
starter.setBinOrHex(mFileType, mFileStreamUri, mFilePath).setInitFile(mInitFileStreamUri, mInitFilePath);
|
starter.setBinOrHex(fileType, fileStreamUri, filePath).setInitFile(initFileStreamUri, initFilePath);
|
||||||
}
|
}
|
||||||
starter.start(this, DfuService.class);
|
starter.start(this, DfuService.class);
|
||||||
}
|
}
|
||||||
@@ -772,10 +774,10 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceSelected(final BluetoothDevice device, final String name) {
|
public void onDeviceSelected(@NonNull final BluetoothDevice device, final String name) {
|
||||||
mSelectedDevice = device;
|
selectedDevice = device;
|
||||||
mUploadButton.setEnabled(mStatusOk);
|
uploadButton.setEnabled(statusOk);
|
||||||
mDeviceNameView.setText(name != null ? name : getString(R.string.not_available));
|
deviceNameView.setText(name != null ? name : getString(R.string.not_available));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -784,15 +786,15 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void showProgressBar() {
|
private void showProgressBar() {
|
||||||
mProgressBar.setVisibility(View.VISIBLE);
|
progressBar.setVisibility(View.VISIBLE);
|
||||||
mTextPercentage.setVisibility(View.VISIBLE);
|
textPercentage.setVisibility(View.VISIBLE);
|
||||||
mTextPercentage.setText(null);
|
textPercentage.setText(null);
|
||||||
mTextUploading.setText(R.string.dfu_status_uploading);
|
textUploading.setText(R.string.dfu_status_uploading);
|
||||||
mTextUploading.setVisibility(View.VISIBLE);
|
textUploading.setVisibility(View.VISIBLE);
|
||||||
mConnectButton.setEnabled(false);
|
connectButton.setEnabled(false);
|
||||||
mSelectFileButton.setEnabled(false);
|
selectFileButton.setEnabled(false);
|
||||||
mUploadButton.setEnabled(true);
|
uploadButton.setEnabled(true);
|
||||||
mUploadButton.setText(R.string.dfu_action_upload_cancel);
|
uploadButton.setText(R.string.dfu_action_upload_cancel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onTransferCompleted() {
|
private void onTransferCompleted() {
|
||||||
@@ -807,9 +809,9 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCancelUpload() {
|
public void onCancelUpload() {
|
||||||
mProgressBar.setIndeterminate(true);
|
progressBar.setIndeterminate(true);
|
||||||
mTextUploading.setText(R.string.dfu_status_aborting);
|
textUploading.setText(R.string.dfu_status_aborting);
|
||||||
mTextPercentage.setText(null);
|
textPercentage.setText(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showErrorMessage(final String message) {
|
private void showErrorMessage(final String message) {
|
||||||
@@ -818,28 +820,28 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void clearUI(final boolean clearDevice) {
|
private void clearUI(final boolean clearDevice) {
|
||||||
mProgressBar.setVisibility(View.INVISIBLE);
|
progressBar.setVisibility(View.INVISIBLE);
|
||||||
mTextPercentage.setVisibility(View.INVISIBLE);
|
textPercentage.setVisibility(View.INVISIBLE);
|
||||||
mTextUploading.setVisibility(View.INVISIBLE);
|
textUploading.setVisibility(View.INVISIBLE);
|
||||||
mConnectButton.setEnabled(true);
|
connectButton.setEnabled(true);
|
||||||
mSelectFileButton.setEnabled(true);
|
selectFileButton.setEnabled(true);
|
||||||
mUploadButton.setEnabled(false);
|
uploadButton.setEnabled(false);
|
||||||
mUploadButton.setText(R.string.dfu_action_upload);
|
uploadButton.setText(R.string.dfu_action_upload);
|
||||||
if (clearDevice) {
|
if (clearDevice) {
|
||||||
mSelectedDevice = null;
|
selectedDevice = null;
|
||||||
mDeviceNameView.setText(R.string.dfu_default_name);
|
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.
|
// 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);
|
fileNameView.setText(null);
|
||||||
mFileTypeView.setText(null);
|
fileTypeView.setText(null);
|
||||||
mFileScopeView.setText(null);
|
fileScopeView.setText(null);
|
||||||
mFileSizeView.setText(null);
|
fileSizeView.setText(null);
|
||||||
mFileStatusView.setText(R.string.dfu_file_status_no_file);
|
fileStatusView.setText(R.string.dfu_file_status_no_file);
|
||||||
mFilePath = null;
|
filePath = null;
|
||||||
mFileStreamUri = null;
|
fileStreamUri = null;
|
||||||
mInitFilePath = null;
|
initFilePath = null;
|
||||||
mInitFileStreamUri = null;
|
initFileStreamUri = null;
|
||||||
mStatusOk = false;
|
statusOk = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showToast(final int messageResId) {
|
private void showToast(final int messageResId) {
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ package no.nordicsemi.android.nrftoolbox.dfu;
|
|||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
import no.nordicsemi.android.nrftoolbox.R;
|
import no.nordicsemi.android.nrftoolbox.R;
|
||||||
@@ -52,7 +54,7 @@ public class DfuInitiatorActivity extends AppCompatActivity implements ScannerFr
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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 Intent intent = getIntent();
|
||||||
final String overwrittenName = intent.getStringExtra(DfuService.EXTRA_DEVICE_NAME);
|
final String overwrittenName = intent.getStringExtra(DfuService.EXTRA_DEVICE_NAME);
|
||||||
final String path = intent.getStringExtra(DfuService.EXTRA_FILE_PATH);
|
final String path = intent.getStringExtra(DfuService.EXTRA_FILE_PATH);
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ public class NotificationActivity extends Activity {
|
|||||||
final Intent parentIntent = new Intent(this, FeaturesActivity.class);
|
final Intent parentIntent = new Intent(this, FeaturesActivity.class);
|
||||||
parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
final Intent startAppIntent = new Intent(this, DfuActivity.class);
|
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 });
|
startActivities(new Intent[] { parentIntent, startAppIntent });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.BaseAdapter;
|
import android.widget.BaseAdapter;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import no.nordicsemi.android.nrftoolbox.R;
|
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.
|
* URLs are specified in res/values/strings_dfu.xml.
|
||||||
*/
|
*/
|
||||||
public class FileBrowserAppsAdapter extends BaseAdapter {
|
public class FileBrowserAppsAdapter extends BaseAdapter {
|
||||||
private final LayoutInflater mInflater;
|
private final LayoutInflater inflater;
|
||||||
private final Resources mResources;
|
private final Resources resources;
|
||||||
|
|
||||||
public FileBrowserAppsAdapter(final Context context) {
|
public FileBrowserAppsAdapter(final Context context) {
|
||||||
mInflater = LayoutInflater.from(context);
|
inflater = LayoutInflater.from(context);
|
||||||
mResources = context.getResources();
|
resources = context.getResources();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getCount() {
|
public int getCount() {
|
||||||
return mResources.getStringArray(R.array.dfu_app_file_browser).length;
|
return resources.getStringArray(R.array.dfu_app_file_browser).length;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getItem(int position) {
|
public Object getItem(final int position) {
|
||||||
return mResources.getStringArray(R.array.dfu_app_file_browser_action)[position];
|
return resources.getStringArray(R.array.dfu_app_file_browser_action)[position];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getItemId(int position) {
|
public long getItemId(final int position) {
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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;
|
View view = convertView;
|
||||||
if (view == null) {
|
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;
|
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);
|
item.getCompoundDrawablesRelative()[0].setLevel(position);
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,17 +21,17 @@
|
|||||||
*/
|
*/
|
||||||
package no.nordicsemi.android.nrftoolbox.dfu.fragment;
|
package no.nordicsemi.android.nrftoolbox.dfu.fragment;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
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 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.R;
|
||||||
import no.nordicsemi.android.nrftoolbox.dfu.DfuService;
|
import no.nordicsemi.android.nrftoolbox.dfu.DfuService;
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ import no.nordicsemi.android.nrftoolbox.dfu.DfuService;
|
|||||||
public class UploadCancelFragment extends DialogFragment {
|
public class UploadCancelFragment extends DialogFragment {
|
||||||
private static final String TAG = "UploadCancelFragment";
|
private static final String TAG = "UploadCancelFragment";
|
||||||
|
|
||||||
private CancelFragmentListener mListener;
|
private CancelFragmentListener listener;
|
||||||
|
|
||||||
public interface CancelFragmentListener {
|
public interface CancelFragmentListener {
|
||||||
void onCancelUpload();
|
void onCancelUpload();
|
||||||
@@ -52,11 +52,11 @@ public class UploadCancelFragment extends DialogFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(final Activity activity) {
|
public void onAttach(@NonNull final Context context) {
|
||||||
super.onAttach(activity);
|
super.onAttach(context);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mListener = (CancelFragmentListener) activity;
|
listener = (CancelFragmentListener) context;
|
||||||
} catch (final ClassCastException e) {
|
} catch (final ClassCastException e) {
|
||||||
Log.d(TAG, "The parent Activity must implement CancelFragmentListener interface");
|
Log.d(TAG, "The parent Activity must implement CancelFragmentListener interface");
|
||||||
}
|
}
|
||||||
@@ -65,20 +65,20 @@ public class UploadCancelFragment extends DialogFragment {
|
|||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public Dialog onCreateDialog(final Bundle savedInstanceState) {
|
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) -> {
|
.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);
|
final Intent pauseAction = new Intent(DfuService.BROADCAST_ACTION);
|
||||||
pauseAction.putExtra(DfuService.EXTRA_ACTION, DfuService.ACTION_ABORT);
|
pauseAction.putExtra(DfuService.EXTRA_ACTION, DfuService.ACTION_ABORT);
|
||||||
manager.sendBroadcast(pauseAction);
|
manager.sendBroadcast(pauseAction);
|
||||||
|
|
||||||
mListener.onCancelUpload();
|
listener.onCancelUpload();
|
||||||
}).setNegativeButton(R.string.no, (dialog, which) -> dialog.cancel()).create();
|
}).setNegativeButton(R.string.no, (dialog, which) -> dialog.cancel()).create();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCancel(final DialogInterface dialog) {
|
public void onCancel(@NonNull final DialogInterface dialog) {
|
||||||
final LocalBroadcastManager manager = LocalBroadcastManager.getInstance(getActivity());
|
final LocalBroadcastManager manager = LocalBroadcastManager.getInstance(requireContext());
|
||||||
final Intent pauseAction = new Intent(DfuService.BROADCAST_ACTION);
|
final Intent pauseAction = new Intent(DfuService.BROADCAST_ACTION);
|
||||||
pauseAction.putExtra(DfuService.EXTRA_ACTION, DfuService.ACTION_RESUME);
|
pauseAction.putExtra(DfuService.EXTRA_ACTION, DfuService.ACTION_RESUME);
|
||||||
manager.sendBroadcast(pauseAction);
|
manager.sendBroadcast(pauseAction);
|
||||||
|
|||||||
@@ -36,7 +36,12 @@ public class ZipInfoFragment extends DialogFragment {
|
|||||||
@Override
|
@Override
|
||||||
@NonNull
|
@NonNull
|
||||||
public Dialog onCreateDialog(final Bundle savedInstanceState) {
|
public Dialog onCreateDialog(final Bundle savedInstanceState) {
|
||||||
final View view = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_zip_info, null);
|
final View view = LayoutInflater.from(requireContext())
|
||||||
return new AlertDialog.Builder(getActivity()).setView(view).setTitle(R.string.dfu_file_info).setPositiveButton(R.string.ok, null).create();
|
.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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ public class AboutDfuPreference extends Preference {
|
|||||||
protected void onClick() {
|
protected void onClick() {
|
||||||
final Context context = getContext();
|
final Context context = getContext();
|
||||||
final Intent intent = new Intent(Intent.ACTION_VIEW,
|
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.addCategory(Intent.CATEGORY_DEFAULT);
|
||||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
|
||||||
|
|||||||
@@ -34,44 +34,44 @@ import android.widget.TextView;
|
|||||||
import no.nordicsemi.android.nrftoolbox.R;
|
import no.nordicsemi.android.nrftoolbox.R;
|
||||||
|
|
||||||
public class ExpandableRecordAdapter extends BaseExpandableListAdapter {;
|
public class ExpandableRecordAdapter extends BaseExpandableListAdapter {;
|
||||||
private final GlucoseManager mGlucoseManager;
|
private final GlucoseManager glucoseManager;
|
||||||
private final LayoutInflater mInflater;
|
private final LayoutInflater inflater;
|
||||||
private final Context mContext;
|
private final Context context;
|
||||||
private SparseArray<GlucoseRecord> mRecords;
|
private SparseArray<GlucoseRecord> records;
|
||||||
|
|
||||||
public ExpandableRecordAdapter(final Context context, final GlucoseManager manager) {
|
public ExpandableRecordAdapter(final Context context, final GlucoseManager manager) {
|
||||||
mGlucoseManager = manager;
|
glucoseManager = manager;
|
||||||
mContext = context;
|
this.context = context;
|
||||||
mInflater = LayoutInflater.from(context);
|
inflater = LayoutInflater.from(context);
|
||||||
mRecords = manager.getRecords().clone();
|
records = manager.getRecords().clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void notifyDataSetChanged() {
|
public void notifyDataSetChanged() {
|
||||||
mRecords = mGlucoseManager.getRecords().clone();
|
records = glucoseManager.getRecords().clone();
|
||||||
super.notifyDataSetChanged();
|
super.notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getGroupCount() {
|
public int getGroupCount() {
|
||||||
return mRecords.size();
|
return records.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getGroup(final int groupPosition) {
|
public Object getGroup(final int groupPosition) {
|
||||||
return mRecords.valueAt(groupPosition);
|
return records.valueAt(groupPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getGroupId(final int groupPosition) {
|
public long getGroupId(final int groupPosition) {
|
||||||
return mRecords.keyAt(groupPosition);
|
return records.keyAt(groupPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View getGroupView(final int position, boolean isExpanded, final View convertView, final ViewGroup parent) {
|
public View getGroupView(final int position, boolean isExpanded, final View convertView, final ViewGroup parent) {
|
||||||
View view = convertView;
|
View view = convertView;
|
||||||
if (view == null) {
|
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();
|
final GroupViewHolder holder = new GroupViewHolder();
|
||||||
holder.time = view.findViewById(R.id.time);
|
holder.time = view.findViewById(R.id.time);
|
||||||
@@ -83,16 +83,16 @@ public class ExpandableRecordAdapter extends BaseExpandableListAdapter {;
|
|||||||
if (record == null)
|
if (record == null)
|
||||||
return view; // this may happen during closing the activity
|
return view; // this may happen during closing the activity
|
||||||
final GroupViewHolder holder = (GroupViewHolder) view.getTag();
|
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 {
|
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) {
|
} 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) {
|
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 {
|
} 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;
|
return view;
|
||||||
}
|
}
|
||||||
@@ -123,7 +123,7 @@ public class ExpandableRecordAdapter extends BaseExpandableListAdapter {;
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getChild(final int groupPosition, final int childPosition) {
|
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);
|
final GlucoseRecord record = (GlucoseRecord) getGroup(groupPosition);
|
||||||
String tmp;
|
String tmp;
|
||||||
switch (childIdToItemId(childPosition, record)) {
|
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) {
|
public View getChildView(final int groupPosition, final int childPosition, final boolean isLastChild, final View convertView, final ViewGroup parent) {
|
||||||
View view = convertView;
|
View view = convertView;
|
||||||
if (view == null) {
|
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();
|
final ChildViewHolder holder = new ChildViewHolder();
|
||||||
holder.title = view.findViewById(android.R.id.text1);
|
holder.title = view.findViewById(android.R.id.text1);
|
||||||
holder.details = view.findViewById(android.R.id.text2);
|
holder.details = view.findViewById(android.R.id.text2);
|
||||||
|
|||||||
@@ -43,13 +43,13 @@ public class GlucoseActivity extends BleProfileExpandableListActivity implements
|
|||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private static final String TAG = "GlucoseActivity";
|
private static final String TAG = "GlucoseActivity";
|
||||||
|
|
||||||
private BaseExpandableListAdapter mAdapter;
|
private BaseExpandableListAdapter adapter;
|
||||||
private GlucoseManager mGlucoseManager;
|
private GlucoseManager glucoseManager;
|
||||||
|
|
||||||
private View mControlPanelStd;
|
private View controlPanelStd;
|
||||||
private View mControlPanelAbort;
|
private View controlPanelAbort;
|
||||||
private TextView mUnitView;
|
private TextView unitView;
|
||||||
private TextView mBatteryLevelView;
|
private TextView batteryLevelView;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreateView(final Bundle savedInstanceState) {
|
protected void onCreateView(final Bundle savedInstanceState) {
|
||||||
@@ -58,14 +58,14 @@ public class GlucoseActivity extends BleProfileExpandableListActivity implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setGUI() {
|
private void setGUI() {
|
||||||
mUnitView = findViewById(R.id.unit);
|
unitView = findViewById(R.id.unit);
|
||||||
mControlPanelStd = findViewById(R.id.gls_control_std);
|
controlPanelStd = findViewById(R.id.gls_control_std);
|
||||||
mControlPanelAbort = findViewById(R.id.gls_control_abort);
|
controlPanelAbort = findViewById(R.id.gls_control_abort);
|
||||||
mBatteryLevelView = findViewById(R.id.battery);
|
batteryLevelView = findViewById(R.id.battery);
|
||||||
|
|
||||||
findViewById(R.id.action_last).setOnClickListener(v -> mGlucoseManager.getLastRecord());
|
findViewById(R.id.action_last).setOnClickListener(v -> glucoseManager.getLastRecord());
|
||||||
findViewById(R.id.action_all).setOnClickListener(v -> mGlucoseManager.getAllRecords());
|
findViewById(R.id.action_all).setOnClickListener(v -> glucoseManager.getAllRecords());
|
||||||
findViewById(R.id.action_abort).setOnClickListener(v -> mGlucoseManager.abort());
|
findViewById(R.id.action_abort).setOnClickListener(v -> glucoseManager.abort());
|
||||||
|
|
||||||
// create popup menu attached to the button More
|
// create popup menu attached to the button More
|
||||||
findViewById(R.id.action_more).setOnClickListener(v -> {
|
findViewById(R.id.action_more).setOnClickListener(v -> {
|
||||||
@@ -76,12 +76,12 @@ public class GlucoseActivity extends BleProfileExpandableListActivity implements
|
|||||||
menu.show();
|
menu.show();
|
||||||
});
|
});
|
||||||
|
|
||||||
setListAdapter(mAdapter = new ExpandableRecordAdapter(this, mGlucoseManager));
|
setListAdapter(adapter = new ExpandableRecordAdapter(this, glucoseManager));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected LoggableBleManager<GlucoseManagerCallbacks> initializeManager() {
|
protected LoggableBleManager<GlucoseManagerCallbacks> initializeManager() {
|
||||||
GlucoseManager manager = mGlucoseManager = GlucoseManager.getGlucoseManager(getApplicationContext());
|
GlucoseManager manager = glucoseManager = GlucoseManager.getGlucoseManager(getApplicationContext());
|
||||||
manager.setGattCallbacks(this);
|
manager.setGattCallbacks(this);
|
||||||
return manager;
|
return manager;
|
||||||
}
|
}
|
||||||
@@ -90,16 +90,16 @@ public class GlucoseActivity extends BleProfileExpandableListActivity implements
|
|||||||
public boolean onMenuItemClick(final MenuItem item) {
|
public boolean onMenuItemClick(final MenuItem item) {
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
case R.id.action_refresh:
|
case R.id.action_refresh:
|
||||||
mGlucoseManager.refreshRecords();
|
glucoseManager.refreshRecords();
|
||||||
break;
|
break;
|
||||||
case R.id.action_first:
|
case R.id.action_first:
|
||||||
mGlucoseManager.getFirstRecord();
|
glucoseManager.getFirstRecord();
|
||||||
break;
|
break;
|
||||||
case R.id.action_clear:
|
case R.id.action_clear:
|
||||||
mGlucoseManager.clear();
|
glucoseManager.clear();
|
||||||
break;
|
break;
|
||||||
case R.id.action_delete_all:
|
case R.id.action_delete_all:
|
||||||
mGlucoseManager.deleteAllRecords();
|
glucoseManager.deleteAllRecords();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -127,14 +127,14 @@ public class GlucoseActivity extends BleProfileExpandableListActivity implements
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setDefaultUI() {
|
protected void setDefaultUI() {
|
||||||
mGlucoseManager.clear();
|
glucoseManager.clear();
|
||||||
mBatteryLevelView.setText(R.string.not_available);
|
batteryLevelView.setText(R.string.not_available);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setOperationInProgress(final boolean progress) {
|
private void setOperationInProgress(final boolean progress) {
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
mControlPanelStd.setVisibility(!progress ? View.VISIBLE : View.GONE);
|
controlPanelStd.setVisibility(!progress ? View.VISIBLE : View.GONE);
|
||||||
mControlPanelAbort.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) {
|
public void onDeviceDisconnected(@NonNull final BluetoothDevice device) {
|
||||||
super.onDeviceDisconnected(device);
|
super.onDeviceDisconnected(device);
|
||||||
setOperationInProgress(false);
|
setOperationInProgress(false);
|
||||||
runOnUiThread(() -> mBatteryLevelView.setText(R.string.not_available));
|
runOnUiThread(() -> batteryLevelView.setText(R.string.not_available));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onOperationStarted(final BluetoothDevice device) {
|
public void onOperationStarted(@NonNull final BluetoothDevice device) {
|
||||||
setOperationInProgress(true);
|
setOperationInProgress(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onOperationCompleted(final BluetoothDevice device) {
|
public void onOperationCompleted(@NonNull final BluetoothDevice device) {
|
||||||
setOperationInProgress(false);
|
setOperationInProgress(false);
|
||||||
|
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
final SparseArray<GlucoseRecord> records = mGlucoseManager.getRecords();
|
final SparseArray<GlucoseRecord> records = glucoseManager.getRecords();
|
||||||
if (records.size() > 0) {
|
if (records.size() > 0) {
|
||||||
final int unit = records.valueAt(0).unit;
|
final int unit = records.valueAt(0).unit;
|
||||||
mUnitView.setVisibility(View.VISIBLE);
|
unitView.setVisibility(View.VISIBLE);
|
||||||
mUnitView.setText(unit == GlucoseRecord.UNIT_kgpl ? R.string.gls_unit_mgpdl : R.string.gls_unit_mmolpl);
|
unitView.setText(unit == GlucoseRecord.UNIT_kgpl ? R.string.gls_unit_mgpdl : R.string.gls_unit_mmolpl);
|
||||||
} else {
|
} else {
|
||||||
mUnitView.setVisibility(View.GONE);
|
unitView.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
mAdapter.notifyDataSetChanged();
|
adapter.notifyDataSetChanged();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onOperationAborted(final BluetoothDevice device) {
|
public void onOperationAborted(@NonNull final BluetoothDevice device) {
|
||||||
setOperationInProgress(false);
|
setOperationInProgress(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onOperationNotSupported(final BluetoothDevice device) {
|
public void onOperationNotSupported(@NonNull final BluetoothDevice device) {
|
||||||
setOperationInProgress(false);
|
setOperationInProgress(false);
|
||||||
showToast(R.string.gls_operation_not_supported);
|
showToast(R.string.gls_operation_not_supported);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onOperationFailed(final BluetoothDevice device) {
|
public void onOperationFailed(@NonNull final BluetoothDevice device) {
|
||||||
setOperationInProgress(false);
|
setOperationInProgress(false);
|
||||||
showToast(R.string.gls_operation_failed);
|
showToast(R.string.gls_operation_failed);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDatasetChanged(final BluetoothDevice device) {
|
public void onDataSetChanged(@NonNull final BluetoothDevice device) {
|
||||||
// Do nothing. Refreshing the list is done in onOperationCompleted
|
// Do nothing. Refreshing the list is done in onOperationCompleted
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNumberOfRecordsRequested(final BluetoothDevice device, final int value) {
|
public void onNumberOfRecordsRequested(@NonNull final BluetoothDevice device, final int value) {
|
||||||
if (value == 0)
|
if (value == 0)
|
||||||
showToast(R.string.gls_progress_zero);
|
showToast(R.string.gls_progress_zero);
|
||||||
else
|
else
|
||||||
@@ -199,6 +199,6 @@ public class GlucoseActivity extends BleProfileExpandableListActivity implements
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) {
|
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)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
package no.nordicsemi.android.nrftoolbox.gls;
|
package no.nordicsemi.android.nrftoolbox.gls;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.bluetooth.BluetoothGatt;
|
import android.bluetooth.BluetoothGatt;
|
||||||
import android.bluetooth.BluetoothGattCharacteristic;
|
import android.bluetooth.BluetoothGattCharacteristic;
|
||||||
@@ -52,7 +53,7 @@ public class GlucoseManager extends BatteryManager<GlucoseManagerCallbacks> {
|
|||||||
private static final String TAG = "GlucoseManager";
|
private static final String TAG = "GlucoseManager";
|
||||||
|
|
||||||
/** Glucose service UUID */
|
/** 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 */
|
/** Glucose Measurement characteristic UUID */
|
||||||
private final static UUID GM_CHARACTERISTIC = UUID.fromString("00002A18-0000-1000-8000-00805f9b34fb");
|
private final static UUID GM_CHARACTERISTIC = UUID.fromString("00002A18-0000-1000-8000-00805f9b34fb");
|
||||||
/** Glucose Measurement Context characteristic UUID */
|
/** Glucose Measurement Context characteristic UUID */
|
||||||
@@ -62,39 +63,39 @@ public class GlucoseManager extends BatteryManager<GlucoseManagerCallbacks> {
|
|||||||
/** Record Access Control Point characteristic UUID */
|
/** Record Access Control Point characteristic UUID */
|
||||||
private final static UUID RACP_CHARACTERISTIC = UUID.fromString("00002A52-0000-1000-8000-00805f9b34fb");
|
private final static UUID RACP_CHARACTERISTIC = UUID.fromString("00002A52-0000-1000-8000-00805f9b34fb");
|
||||||
|
|
||||||
private BluetoothGattCharacteristic mGlucoseMeasurementCharacteristic;
|
private BluetoothGattCharacteristic glucoseMeasurementCharacteristic;
|
||||||
private BluetoothGattCharacteristic mGlucoseMeasurementContextCharacteristic;
|
private BluetoothGattCharacteristic glucoseMeasurementContextCharacteristic;
|
||||||
private BluetoothGattCharacteristic mRecordAccessControlPointCharacteristic;
|
private BluetoothGattCharacteristic recordAccessControlPointCharacteristic;
|
||||||
|
|
||||||
private final SparseArray<GlucoseRecord> mRecords = new SparseArray<>();
|
private final SparseArray<GlucoseRecord> records = new SparseArray<>();
|
||||||
private Handler mHandler;
|
private Handler handler;
|
||||||
private static GlucoseManager mInstance;
|
private static GlucoseManager instance;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the singleton implementation of GlucoseManager.
|
* Returns the singleton implementation of GlucoseManager.
|
||||||
*/
|
*/
|
||||||
public static GlucoseManager getGlucoseManager(final Context context) {
|
static GlucoseManager getGlucoseManager(@NonNull final Context context) {
|
||||||
if (mInstance == null)
|
if (instance == null)
|
||||||
mInstance = new GlucoseManager(context);
|
instance = new GlucoseManager(context);
|
||||||
return mInstance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
private GlucoseManager(final Context context) {
|
private GlucoseManager(final Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
mHandler = new Handler();
|
handler = new Handler();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
protected BatteryManagerGattCallback getGattCallback() {
|
protected BatteryManagerGattCallback getGattCallback() {
|
||||||
return mGattCallback;
|
return gattCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BluetoothGatt callbacks for connection/disconnection, service discovery,
|
* BluetoothGatt callbacks for connection/disconnection, service discovery,
|
||||||
* receiving notification, etc.
|
* receiving notification, etc.
|
||||||
*/
|
*/
|
||||||
private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() {
|
private final BatteryManagerGattCallback gattCallback = new BatteryManagerGattCallback() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initialize() {
|
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
|
// However... the original approach works for the Battery Level CCCD, which makes it
|
||||||
// even weirder.
|
// even weirder.
|
||||||
/*
|
/*
|
||||||
gatt.setCharacteristicNotification(mGlucoseMeasurementCharacteristic, true);
|
gatt.setCharacteristicNotification(glucoseMeasurementCharacteristic, true);
|
||||||
if (mGlucoseMeasurementContextCharacteristic != null) {
|
if (glucoseMeasurementContextCharacteristic != null) {
|
||||||
device.setCharacteristicNotification(mGlucoseMeasurementContextCharacteristic, true);
|
device.setCharacteristicNotification(glucoseMeasurementContextCharacteristic, true);
|
||||||
}
|
}
|
||||||
device.setCharacteristicNotification(mRecordAccessControlPointCharacteristic, true);
|
device.setCharacteristicNotification(recordAccessControlPointCharacteristic, true);
|
||||||
*/
|
*/
|
||||||
setNotificationCallback(mGlucoseMeasurementCharacteristic)
|
setNotificationCallback(glucoseMeasurementContextCharacteristic)
|
||||||
.with(new GlucoseMeasurementDataCallback() {
|
.with(new GlucoseMeasurementDataCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
|
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;
|
record.status = status != null ? status.value : 0;
|
||||||
|
|
||||||
// insert the new record to storage
|
// insert the new record to storage
|
||||||
mRecords.put(record.sequenceNumber, record);
|
records.put(record.sequenceNumber, record);
|
||||||
mHandler.post(() -> {
|
handler.post(() -> {
|
||||||
// if there is no context information following the measurement data,
|
// if there is no context information following the measurement data,
|
||||||
// notify callback about the new record
|
// notify callback about the new record
|
||||||
if (!contextInformationFollows)
|
if (!contextInformationFollows)
|
||||||
mCallbacks.onDatasetChanged(device);
|
callbacks.onDataSetChanged(device);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
setNotificationCallback(mGlucoseMeasurementContextCharacteristic)
|
setNotificationCallback(glucoseMeasurementContextCharacteristic)
|
||||||
.with(new GlucoseMeasurementContextDataCallback() {
|
.with(new GlucoseMeasurementContextDataCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
|
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 Integer exerciseIntensity, @Nullable final Medication medication,
|
||||||
@Nullable final Float medicationAmount, @Nullable final Integer medicationUnit,
|
@Nullable final Float medicationAmount, @Nullable final Integer medicationUnit,
|
||||||
@Nullable final Float HbA1c) {
|
@Nullable final Float HbA1c) {
|
||||||
final GlucoseRecord record = mRecords.get(sequenceNumber);
|
final GlucoseRecord record = records.get(sequenceNumber);
|
||||||
if (record == null) {
|
if (record == null) {
|
||||||
DebugLogger.w(TAG, "Context information with unknown sequence number: " + sequenceNumber);
|
DebugLogger.w(TAG, "Context information with unknown sequence number: " + sequenceNumber);
|
||||||
return;
|
return;
|
||||||
@@ -186,14 +187,14 @@ public class GlucoseManager extends BatteryManager<GlucoseManagerCallbacks> {
|
|||||||
context.medicationUnit = medicationUnit != null ? medicationUnit : UNIT_mg;
|
context.medicationUnit = medicationUnit != null ? medicationUnit : UNIT_mg;
|
||||||
context.HbA1c = HbA1c != null ? HbA1c : 0;
|
context.HbA1c = HbA1c != null ? HbA1c : 0;
|
||||||
|
|
||||||
mHandler.post(() -> {
|
handler.post(() -> {
|
||||||
// notify callback about the new record
|
// notify callback about the new record
|
||||||
mCallbacks.onDatasetChanged(device);
|
callbacks.onDataSetChanged(device);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
setIndicationCallback(mRecordAccessControlPointCharacteristic)
|
setIndicationCallback(recordAccessControlPointCharacteristic)
|
||||||
.with(new RecordAccessControlPointDataCallback() {
|
.with(new RecordAccessControlPointDataCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
|
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);
|
super.onDataReceived(device, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SwitchIntDef")
|
||||||
@Override
|
@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) {
|
switch (requestCode) {
|
||||||
case RACP_OP_CODE_ABORT_OPERATION:
|
case RACP_OP_CODE_ABORT_OPERATION:
|
||||||
mCallbacks.onOperationAborted(device);
|
callbacks.onOperationAborted(device);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
mCallbacks.onOperationCompleted(device);
|
callbacks.onOperationCompleted(device);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRecordAccessOperationCompletedWithNoRecordsFound(@NonNull final BluetoothDevice device, final int requestCode) {
|
public void onRecordAccessOperationCompletedWithNoRecordsFound(@NonNull final BluetoothDevice device,
|
||||||
mCallbacks.onOperationCompleted(device);
|
@RACPOpCode final int requestCode) {
|
||||||
|
callbacks.onOperationCompleted(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNumberOfRecordsReceived(@NonNull final BluetoothDevice device, final int numberOfRecords) {
|
public void onNumberOfRecordsReceived(@NonNull final BluetoothDevice device, final int numberOfRecords) {
|
||||||
mCallbacks.onNumberOfRecordsRequested(device, numberOfRecords);
|
callbacks.onNumberOfRecordsRequested(device, numberOfRecords);
|
||||||
if (numberOfRecords > 0) {
|
if (numberOfRecords > 0) {
|
||||||
if (mRecords.size() > 0) {
|
if (records.size() > 0) {
|
||||||
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))
|
RecordAccessControlPointData.reportStoredRecordsGreaterThenOrEqualTo(sequenceNumber))
|
||||||
.enqueue();
|
.enqueue();
|
||||||
} else {
|
} else {
|
||||||
writeCharacteristic(mRecordAccessControlPointCharacteristic,
|
writeCharacteristic(recordAccessControlPointCharacteristic,
|
||||||
RecordAccessControlPointData.reportAllStoredRecords())
|
RecordAccessControlPointData.reportAllStoredRecords())
|
||||||
.enqueue();
|
.enqueue();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mCallbacks.onOperationCompleted(device);
|
callbacks.onOperationCompleted(device);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRecordAccessOperationError(@NonNull final BluetoothDevice device,
|
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 + ")");
|
log(Log.WARN, "Record Access operation failed (error " + errorCode + ")");
|
||||||
if (errorCode == RACP_ERROR_OP_CODE_NOT_SUPPORTED) {
|
if (errorCode == RACP_ERROR_OP_CODE_NOT_SUPPORTED) {
|
||||||
mCallbacks.onOperationNotSupported(device);
|
callbacks.onOperationNotSupported(device);
|
||||||
} else {
|
} else {
|
||||||
mCallbacks.onOperationFailed(device);
|
callbacks.onOperationFailed(device);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
enableNotifications(mGlucoseMeasurementCharacteristic).enqueue();
|
enableNotifications(glucoseMeasurementContextCharacteristic).enqueue();
|
||||||
enableNotifications(mGlucoseMeasurementContextCharacteristic).enqueue();
|
enableNotifications(glucoseMeasurementContextCharacteristic).enqueue();
|
||||||
enableIndications(mRecordAccessControlPointCharacteristic)
|
enableIndications(recordAccessControlPointCharacteristic)
|
||||||
.fail((device, status) -> log(Log.WARN, "Failed to enabled Record Access Control Point indications (error " + status + ")"))
|
.fail((device, status) -> log(Log.WARN, "Failed to enabled Record Access Control Point indications (error " + status + ")"))
|
||||||
.enqueue();
|
.enqueue();
|
||||||
}
|
}
|
||||||
@@ -260,24 +266,24 @@ public class GlucoseManager extends BatteryManager<GlucoseManagerCallbacks> {
|
|||||||
public boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) {
|
public boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) {
|
||||||
final BluetoothGattService service = gatt.getService(GLS_SERVICE_UUID);
|
final BluetoothGattService service = gatt.getService(GLS_SERVICE_UUID);
|
||||||
if (service != null) {
|
if (service != null) {
|
||||||
mGlucoseMeasurementCharacteristic = service.getCharacteristic(GM_CHARACTERISTIC);
|
glucoseMeasurementCharacteristic = service.getCharacteristic(GM_CHARACTERISTIC);
|
||||||
mGlucoseMeasurementContextCharacteristic = service.getCharacteristic(GM_CONTEXT_CHARACTERISTIC);
|
glucoseMeasurementContextCharacteristic = service.getCharacteristic(GM_CONTEXT_CHARACTERISTIC);
|
||||||
mRecordAccessControlPointCharacteristic = service.getCharacteristic(RACP_CHARACTERISTIC);
|
recordAccessControlPointCharacteristic = service.getCharacteristic(RACP_CHARACTERISTIC);
|
||||||
}
|
}
|
||||||
return mGlucoseMeasurementCharacteristic != null && mRecordAccessControlPointCharacteristic != null;
|
return glucoseMeasurementCharacteristic != null && recordAccessControlPointCharacteristic != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean isOptionalServiceSupported(@NonNull BluetoothGatt gatt) {
|
protected boolean isOptionalServiceSupported(@NonNull BluetoothGatt gatt) {
|
||||||
super.isOptionalServiceSupported(gatt);
|
super.isOptionalServiceSupported(gatt);
|
||||||
return mGlucoseMeasurementContextCharacteristic != null;
|
return glucoseMeasurementContextCharacteristic != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDeviceDisconnected() {
|
protected void onDeviceDisconnected() {
|
||||||
mGlucoseMeasurementCharacteristic = null;
|
glucoseMeasurementCharacteristic = null;
|
||||||
mGlucoseMeasurementContextCharacteristic = null;
|
glucoseMeasurementContextCharacteristic = null;
|
||||||
mRecordAccessControlPointCharacteristic = null;
|
recordAccessControlPointCharacteristic = null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -286,16 +292,16 @@ public class GlucoseManager extends BatteryManager<GlucoseManagerCallbacks> {
|
|||||||
*
|
*
|
||||||
* @return the records list.
|
* @return the records list.
|
||||||
*/
|
*/
|
||||||
public SparseArray<GlucoseRecord> getRecords() {
|
SparseArray<GlucoseRecord> getRecords() {
|
||||||
return mRecords;
|
return records;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears the records list locally.
|
* Clears the records list locally.
|
||||||
*/
|
*/
|
||||||
public void clear() {
|
public void clear() {
|
||||||
mRecords.clear();
|
records.clear();
|
||||||
mCallbacks.onOperationCompleted(getBluetoothDevice());
|
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
|
* 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.
|
* Control Point indication with status code Success or other in case of error.
|
||||||
*/
|
*/
|
||||||
public void getLastRecord() {
|
void getLastRecord() {
|
||||||
if (mRecordAccessControlPointCharacteristic == null)
|
if (recordAccessControlPointCharacteristic == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
mCallbacks.onOperationStarted(getBluetoothDevice());
|
callbacks.onOperationStarted(getBluetoothDevice());
|
||||||
writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.reportLastStoredRecord())
|
writeCharacteristic(recordAccessControlPointCharacteristic, RecordAccessControlPointData.reportLastStoredRecord())
|
||||||
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
|
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
|
||||||
.enqueue();
|
.enqueue();
|
||||||
}
|
}
|
||||||
@@ -319,13 +325,13 @@ public class GlucoseManager extends BatteryManager<GlucoseManagerCallbacks> {
|
|||||||
* returned to Glucose Measurement characteristic as a notification followed by Record Access
|
* 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.
|
* Control Point indication with status code Success or other in case of error.
|
||||||
*/
|
*/
|
||||||
public void getFirstRecord() {
|
void getFirstRecord() {
|
||||||
if (mRecordAccessControlPointCharacteristic == null)
|
if (recordAccessControlPointCharacteristic == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
mCallbacks.onOperationStarted(getBluetoothDevice());
|
callbacks.onOperationStarted(getBluetoothDevice());
|
||||||
writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.reportFirstStoredRecord())
|
writeCharacteristic(recordAccessControlPointCharacteristic, RecordAccessControlPointData.reportFirstStoredRecord())
|
||||||
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
|
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
|
||||||
.enqueue();
|
.enqueue();
|
||||||
}
|
}
|
||||||
@@ -336,13 +342,13 @@ public class GlucoseManager extends BatteryManager<GlucoseManagerCallbacks> {
|
|||||||
* will be returned to Glucose Measurement characteristic as a notification followed by
|
* 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.
|
* Record Access Control Point indication with status code Success or other in case of error.
|
||||||
*/
|
*/
|
||||||
public void getAllRecords() {
|
void getAllRecords() {
|
||||||
if (mRecordAccessControlPointCharacteristic == null)
|
if (recordAccessControlPointCharacteristic == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
mCallbacks.onOperationStarted(getBluetoothDevice());
|
callbacks.onOperationStarted(getBluetoothDevice());
|
||||||
writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.reportNumberOfAllStoredRecords())
|
writeCharacteristic(recordAccessControlPointCharacteristic, RecordAccessControlPointData.reportNumberOfAllStoredRecords())
|
||||||
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
|
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
|
||||||
.enqueue();
|
.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.
|
* 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()}).
|
* However if there are no records, it will download all existing (using {@link #getAllRecords()}).
|
||||||
*/
|
*/
|
||||||
public void refreshRecords() {
|
void refreshRecords() {
|
||||||
if (mRecordAccessControlPointCharacteristic == null)
|
if (recordAccessControlPointCharacteristic == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (mRecords.size() == 0) {
|
if (records.size() == 0) {
|
||||||
getAllRecords();
|
getAllRecords();
|
||||||
} else {
|
} else {
|
||||||
mCallbacks.onOperationStarted(getBluetoothDevice());
|
callbacks.onOperationStarted(getBluetoothDevice());
|
||||||
|
|
||||||
// obtain the last sequence number
|
// 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))
|
RecordAccessControlPointData.reportStoredRecordsGreaterThenOrEqualTo(sequenceNumber))
|
||||||
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
|
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
|
||||||
.enqueue();
|
.enqueue();
|
||||||
@@ -381,11 +387,11 @@ public class GlucoseManager extends BatteryManager<GlucoseManagerCallbacks> {
|
|||||||
/**
|
/**
|
||||||
* Sends abort operation signal to the device.
|
* Sends abort operation signal to the device.
|
||||||
*/
|
*/
|
||||||
public void abort() {
|
void abort() {
|
||||||
if (mRecordAccessControlPointCharacteristic == null)
|
if (recordAccessControlPointCharacteristic == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.abortOperation())
|
writeCharacteristic(recordAccessControlPointCharacteristic, RecordAccessControlPointData.abortOperation())
|
||||||
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
|
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
|
||||||
.enqueue();
|
.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
|
* 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.
|
* indication with status code Success (or other in case of error) will be send.
|
||||||
*/
|
*/
|
||||||
public void deleteAllRecords() {
|
void deleteAllRecords() {
|
||||||
if (mRecordAccessControlPointCharacteristic == null)
|
if (recordAccessControlPointCharacteristic == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
mCallbacks.onOperationStarted(getBluetoothDevice());
|
callbacks.onOperationStarted(getBluetoothDevice());
|
||||||
writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.deleteAllStoredRecords())
|
writeCharacteristic(recordAccessControlPointCharacteristic, RecordAccessControlPointData.deleteAllStoredRecords())
|
||||||
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
|
.with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent"))
|
||||||
.enqueue();
|
.enqueue();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,22 +23,23 @@ package no.nordicsemi.android.nrftoolbox.gls;
|
|||||||
|
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import no.nordicsemi.android.ble.BleManagerCallbacks;
|
import no.nordicsemi.android.ble.BleManagerCallbacks;
|
||||||
import no.nordicsemi.android.nrftoolbox.battery.BatteryManagerCallbacks;
|
import no.nordicsemi.android.nrftoolbox.battery.BatteryManagerCallbacks;
|
||||||
|
|
||||||
public interface GlucoseManagerCallbacks extends 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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,32 +23,34 @@ package no.nordicsemi.android.nrftoolbox.gls;
|
|||||||
|
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public class GlucoseRecord {
|
public class GlucoseRecord {
|
||||||
public static final int UNIT_kgpl = 0;
|
static final int UNIT_kgpl = 0;
|
||||||
public static final int UNIT_molpl = 1;
|
private static final int UNIT_molpl = 1;
|
||||||
|
|
||||||
/** Record sequence number */
|
/** Record sequence number */
|
||||||
protected int sequenceNumber;
|
int sequenceNumber;
|
||||||
/** The base time of the measurement */
|
/** The base time of the measurement */
|
||||||
protected Calendar time;
|
Calendar time;
|
||||||
/** Time offset of the record */
|
/** Time offset of the record */
|
||||||
protected int timeOffset;
|
int timeOffset;
|
||||||
/** The glucose concentration. 0 if not present */
|
/** 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} */
|
/** 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 */
|
/** The type of the record. 0 if not present */
|
||||||
protected int type;
|
int type;
|
||||||
/** The sample location. 0 if unknown */
|
/** The sample location. 0 if unknown */
|
||||||
protected int sampleLocation;
|
int sampleLocation;
|
||||||
/** Sensor status annunciation flags. 0 if not present */
|
/** Sensor status annunciation flags. 0 if not present */
|
||||||
protected int status;
|
int status;
|
||||||
|
|
||||||
protected MeasurementContext context;
|
protected MeasurementContext context;
|
||||||
|
|
||||||
public static class MeasurementContext {
|
@SuppressWarnings("unused")
|
||||||
public static final int UNIT_kg = 0;
|
static class MeasurementContext {
|
||||||
public static final int UNIT_l = 1;
|
static final int UNIT_kg = 0;
|
||||||
|
static final int UNIT_l = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* One of the following:<br/>
|
* One of the following:<br/>
|
||||||
@@ -61,9 +63,9 @@ public class GlucoseRecord {
|
|||||||
* 6 Supper<br/>
|
* 6 Supper<br/>
|
||||||
* 7 Brunch
|
* 7 Brunch
|
||||||
*/
|
*/
|
||||||
protected int carbohydrateId;
|
int carbohydrateId;
|
||||||
/** Number of kilograms of carbohydrate */
|
/** Number of kilograms of carbohydrate */
|
||||||
protected float carbohydrateUnits;
|
float carbohydrateUnits;
|
||||||
/**
|
/**
|
||||||
* One of the following:<br/>
|
* One of the following:<br/>
|
||||||
* 0 Not present<br/>
|
* 0 Not present<br/>
|
||||||
@@ -73,7 +75,7 @@ public class GlucoseRecord {
|
|||||||
* 4 Casual (snacks, drinks, etc.)<br/>
|
* 4 Casual (snacks, drinks, etc.)<br/>
|
||||||
* 5 Bedtime
|
* 5 Bedtime
|
||||||
*/
|
*/
|
||||||
protected int meal;
|
int meal;
|
||||||
/**
|
/**
|
||||||
* One of the following:<br/>
|
* One of the following:<br/>
|
||||||
* 0 Not present<br/>
|
* 0 Not present<br/>
|
||||||
@@ -82,7 +84,7 @@ public class GlucoseRecord {
|
|||||||
* 3 Lab test<br/>
|
* 3 Lab test<br/>
|
||||||
* 15 Tester value not available
|
* 15 Tester value not available
|
||||||
*/
|
*/
|
||||||
protected int tester;
|
int tester;
|
||||||
/**
|
/**
|
||||||
* One of the following:<br/>
|
* One of the following:<br/>
|
||||||
* 0 Not present<br/>
|
* 0 Not present<br/>
|
||||||
@@ -93,11 +95,11 @@ public class GlucoseRecord {
|
|||||||
* 5 No health issues<br/>
|
* 5 No health issues<br/>
|
||||||
* 15 Tester value not available
|
* 15 Tester value not available
|
||||||
*/
|
*/
|
||||||
protected int health;
|
int health;
|
||||||
/** Exercise duration in seconds. 0 if not present */
|
/** Exercise duration in seconds. 0 if not present */
|
||||||
protected int exerciseDuration;
|
int exerciseDuration;
|
||||||
/** Exercise intensity in percent. 0 if not present */
|
/** Exercise intensity in percent. 0 if not present */
|
||||||
protected int exerciseIntensity;
|
int exerciseIntensity;
|
||||||
/**
|
/**
|
||||||
* One of the following:<br/>
|
* One of the following:<br/>
|
||||||
* 0 Not present<br/>
|
* 0 Not present<br/>
|
||||||
@@ -107,12 +109,12 @@ public class GlucoseRecord {
|
|||||||
* 4 Long acting insulin<br/>
|
* 4 Long acting insulin<br/>
|
||||||
* 5 Pre-mixed insulin
|
* 5 Pre-mixed insulin
|
||||||
*/
|
*/
|
||||||
protected int medicationId;
|
int medicationId;
|
||||||
/** Quantity of medication. See {@link #medicationUnit} for the unit. */
|
/** 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}. */
|
/** 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 */
|
/** HbA1c value. 0 if not present */
|
||||||
protected float HbA1c;
|
float HbA1c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ import android.content.Intent;
|
|||||||
import android.graphics.Point;
|
import android.graphics.Point;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
|
||||||
|
import androidx.annotation.IntRange;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import android.view.ViewGroup;
|
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 final static int REFRESH_INTERVAL = 1000; // 1 second interval
|
||||||
|
|
||||||
private Handler mHandler = new Handler();
|
private Handler handler = new Handler();
|
||||||
|
|
||||||
private boolean isGraphInProgress = false;
|
private boolean isGraphInProgress = false;
|
||||||
|
|
||||||
private GraphicalView mGraphView;
|
private GraphicalView graphView;
|
||||||
private LineGraphView mLineGraph;
|
private LineGraphView lineGraph;
|
||||||
private TextView mHRSValue, mHRSPosition;
|
private TextView hrValueView, hrLocationView;
|
||||||
private TextView mBatteryLevelView;
|
private TextView batteryLevelView;
|
||||||
|
|
||||||
private int mHrmValue = 0;
|
private int hrValue = 0;
|
||||||
private int mCounter = 0;
|
private int counter = 0;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreateView(final Bundle savedInstanceState) {
|
protected void onCreateView(final Bundle savedInstanceState) {
|
||||||
@@ -76,17 +78,17 @@ public class HRSActivity extends BleProfileActivity implements HRSManagerCallbac
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setGUI() {
|
private void setGUI() {
|
||||||
mLineGraph = LineGraphView.getLineGraphView();
|
lineGraph = LineGraphView.getLineGraphView();
|
||||||
mHRSValue = findViewById(R.id.text_hrs_value);
|
hrValueView = findViewById(R.id.text_hrs_value);
|
||||||
mHRSPosition = findViewById(R.id.text_hrs_position);
|
hrLocationView = findViewById(R.id.text_hrs_position);
|
||||||
mBatteryLevelView = findViewById(R.id.battery);
|
batteryLevelView = findViewById(R.id.battery);
|
||||||
showGraph();
|
showGraph();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showGraph() {
|
private void showGraph() {
|
||||||
mGraphView = mLineGraph.getView(this);
|
graphView = lineGraph.getView(this);
|
||||||
ViewGroup layout = findViewById(R.id.graph_hrs);
|
ViewGroup layout = findViewById(R.id.graph_hrs);
|
||||||
layout.addView(mGraphView);
|
layout.addView(graphView);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -109,20 +111,20 @@ public class HRSActivity extends BleProfileActivity implements HRSManagerCallbac
|
|||||||
super.onRestoreInstanceState(savedInstanceState);
|
super.onRestoreInstanceState(savedInstanceState);
|
||||||
|
|
||||||
isGraphInProgress = savedInstanceState.getBoolean(GRAPH_STATUS);
|
isGraphInProgress = savedInstanceState.getBoolean(GRAPH_STATUS);
|
||||||
mCounter = savedInstanceState.getInt(GRAPH_COUNTER);
|
counter = savedInstanceState.getInt(GRAPH_COUNTER);
|
||||||
mHrmValue = savedInstanceState.getInt(HR_VALUE);
|
hrValue = savedInstanceState.getInt(HR_VALUE);
|
||||||
|
|
||||||
if (isGraphInProgress)
|
if (isGraphInProgress)
|
||||||
startShowGraph();
|
startShowGraph();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onSaveInstanceState(final Bundle outState) {
|
protected void onSaveInstanceState(@NonNull final Bundle outState) {
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
|
|
||||||
outState.putBoolean(GRAPH_STATUS, isGraphInProgress);
|
outState.putBoolean(GRAPH_STATUS, isGraphInProgress);
|
||||||
outState.putInt(GRAPH_COUNTER, mCounter);
|
outState.putInt(GRAPH_COUNTER, counter);
|
||||||
outState.putInt(HR_VALUE, mHrmValue);
|
outState.putInt(HR_VALUE, hrValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -153,35 +155,35 @@ public class HRSActivity extends BleProfileActivity implements HRSManagerCallbac
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateGraph(final int hrmValue) {
|
private void updateGraph(final int hrmValue) {
|
||||||
mCounter++;
|
counter++;
|
||||||
mLineGraph.addValue(new Point(mCounter, hrmValue));
|
lineGraph.addValue(new Point(counter, hrmValue));
|
||||||
mGraphView.repaint();
|
graphView.repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Runnable mRepeatTask = new Runnable() {
|
private Runnable repeatTask = new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (mHrmValue > 0)
|
if (hrValue > 0)
|
||||||
updateGraph(mHrmValue);
|
updateGraph(hrValue);
|
||||||
if (isGraphInProgress)
|
if (isGraphInProgress)
|
||||||
mHandler.postDelayed(mRepeatTask, REFRESH_INTERVAL);
|
handler.postDelayed(repeatTask, REFRESH_INTERVAL);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void startShowGraph() {
|
void startShowGraph() {
|
||||||
isGraphInProgress = true;
|
isGraphInProgress = true;
|
||||||
mRepeatTask.run();
|
repeatTask.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
void stopShowGraph() {
|
void stopShowGraph() {
|
||||||
isGraphInProgress = false;
|
isGraphInProgress = false;
|
||||||
mHandler.removeCallbacks(mRepeatTask);
|
handler.removeCallbacks(repeatTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected LoggableBleManager<HRSManagerCallbacks> initializeManager() {
|
protected LoggableBleManager<HRSManagerCallbacks> initializeManager() {
|
||||||
final HRSManager manager = HRSManager.getInstance(getApplicationContext());
|
final HRSManager manager = HRSManager.getInstance(getApplicationContext());
|
||||||
manager.setGattCallbacks(this);
|
manager.setManagerCallbacks(this);
|
||||||
return manager;
|
return manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,52 +199,53 @@ public class HRSActivity extends BleProfileActivity implements HRSManagerCallbac
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) {
|
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
|
@Override
|
||||||
public void onBodySensorLocationReceived(@NonNull final BluetoothDevice device, final int sensorLocation) {
|
public void onBodySensorLocationReceived(@NonNull final BluetoothDevice device, final int sensorLocation) {
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
if (sensorLocation >= SENSOR_LOCATION_FIRST && sensorLocation <= SENSOR_LOCATION_LAST) {
|
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 {
|
} else {
|
||||||
mHRSPosition.setText(R.string.hrs_location_other);
|
hrLocationView.setText(R.string.hrs_location_other);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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 Boolean contactDetected,
|
||||||
@Nullable final Integer energyExpanded,
|
@Nullable @IntRange(from = 0) final Integer energyExpanded,
|
||||||
@Nullable final List<Integer> rrIntervals) {
|
@Nullable final List<Integer> rrIntervals) {
|
||||||
mHrmValue = heartRate;
|
hrValue = heartRate;
|
||||||
runOnUiThread(() -> mHRSValue.setText(getString(R.string.hrs_value, heartRate)));
|
runOnUiThread(() -> hrValueView.setText(getString(R.string.hrs_value, heartRate)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceDisconnected(@NonNull final BluetoothDevice device) {
|
public void onDeviceDisconnected(@NonNull final BluetoothDevice device) {
|
||||||
super.onDeviceDisconnected(device);
|
super.onDeviceDisconnected(device);
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
mHRSValue.setText(R.string.not_available_value);
|
hrValueView.setText(R.string.not_available_value);
|
||||||
mHRSPosition.setText(R.string.not_available);
|
hrLocationView.setText(R.string.not_available);
|
||||||
mBatteryLevelView.setText(R.string.not_available);
|
batteryLevelView.setText(R.string.not_available);
|
||||||
stopShowGraph();
|
stopShowGraph();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setDefaultUI() {
|
protected void setDefaultUI() {
|
||||||
mHRSValue.setText(R.string.not_available_value);
|
hrValueView.setText(R.string.not_available_value);
|
||||||
mHRSPosition.setText(R.string.not_available);
|
hrLocationView.setText(R.string.not_available);
|
||||||
mBatteryLevelView.setText(R.string.not_available);
|
batteryLevelView.setText(R.string.not_available);
|
||||||
clearGraph();
|
clearGraph();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearGraph() {
|
private void clearGraph() {
|
||||||
mLineGraph.clearGraph();
|
lineGraph.clearGraph();
|
||||||
mGraphView.repaint();
|
graphView.repaint();
|
||||||
mCounter = 0;
|
counter = 0;
|
||||||
mHrmValue = 0;
|
hrValue = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ import android.bluetooth.BluetoothGatt;
|
|||||||
import android.bluetooth.BluetoothGattCharacteristic;
|
import android.bluetooth.BluetoothGattCharacteristic;
|
||||||
import android.bluetooth.BluetoothGattService;
|
import android.bluetooth.BluetoothGattService;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
|
import androidx.annotation.IntRange;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import android.util.Log;
|
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.BodySensorLocationDataCallback;
|
||||||
import no.nordicsemi.android.ble.common.callback.hr.HeartRateMeasurementDataCallback;
|
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.ble.data.Data;
|
||||||
import no.nordicsemi.android.log.LogContract;
|
import no.nordicsemi.android.log.LogContract;
|
||||||
import no.nordicsemi.android.nrftoolbox.battery.BatteryManager;
|
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 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 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;
|
private static HRSManager managerInstance = null;
|
||||||
|
|
||||||
@@ -73,19 +76,19 @@ public class HRSManager extends BatteryManager<HRSManagerCallbacks> {
|
|||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
protected BatteryManagerGattCallback getGattCallback() {
|
protected BatteryManagerGattCallback getGattCallback() {
|
||||||
return mGattCallback;
|
return gattCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BluetoothGatt callbacks for connection/disconnection, service discovery,
|
* BluetoothGatt callbacks for connection/disconnection, service discovery,
|
||||||
* receiving notification, etc.
|
* receiving notification, etc.
|
||||||
*/
|
*/
|
||||||
private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() {
|
private final BatteryManagerGattCallback gattCallback = new BatteryManagerGattCallback() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initialize() {
|
protected void initialize() {
|
||||||
super.initialize();
|
super.initialize();
|
||||||
readCharacteristic(mBodySensorLocationCharacteristic)
|
readCharacteristic(bodySensorLocationCharacteristic)
|
||||||
.with(new BodySensorLocationDataCallback() {
|
.with(new BodySensorLocationDataCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
|
public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
|
||||||
@@ -95,13 +98,13 @@ public class HRSManager extends BatteryManager<HRSManagerCallbacks> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBodySensorLocationReceived(@NonNull final BluetoothDevice device,
|
public void onBodySensorLocationReceived(@NonNull final BluetoothDevice device,
|
||||||
final int sensorLocation) {
|
@BodySensorLocation final int sensorLocation) {
|
||||||
mCallbacks.onBodySensorLocationReceived(device, sensorLocation);
|
callbacks.onBodySensorLocationReceived(device, sensorLocation);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.fail((device, status) -> log(Log.WARN, "Body Sensor Location characteristic not found"))
|
.fail((device, status) -> log(Log.WARN, "Body Sensor Location characteristic not found"))
|
||||||
.enqueue();
|
.enqueue();
|
||||||
setNotificationCallback(mHeartRateCharacteristic)
|
setNotificationCallback(heartRateCharacteristic)
|
||||||
.with(new HeartRateMeasurementDataCallback() {
|
.with(new HeartRateMeasurementDataCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
|
public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
|
||||||
@@ -111,23 +114,23 @@ public class HRSManager extends BatteryManager<HRSManagerCallbacks> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onHeartRateMeasurementReceived(@NonNull final BluetoothDevice device,
|
public void onHeartRateMeasurementReceived(@NonNull final BluetoothDevice device,
|
||||||
final int heartRate,
|
@IntRange(from = 0) final int heartRate,
|
||||||
@Nullable final Boolean contactDetected,
|
@Nullable final Boolean contactDetected,
|
||||||
@Nullable final Integer energyExpanded,
|
@Nullable @IntRange(from = 0) final Integer energyExpanded,
|
||||||
@Nullable final List<Integer> rrIntervals) {
|
@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
|
@Override
|
||||||
protected boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) {
|
protected boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) {
|
||||||
final BluetoothGattService service = gatt.getService(HR_SERVICE_UUID);
|
final BluetoothGattService service = gatt.getService(HR_SERVICE_UUID);
|
||||||
if (service != null) {
|
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
|
@Override
|
||||||
@@ -135,16 +138,16 @@ public class HRSManager extends BatteryManager<HRSManagerCallbacks> {
|
|||||||
super.isOptionalServiceSupported(gatt);
|
super.isOptionalServiceSupported(gatt);
|
||||||
final BluetoothGattService service = gatt.getService(HR_SERVICE_UUID);
|
final BluetoothGattService service = gatt.getService(HR_SERVICE_UUID);
|
||||||
if (service != null) {
|
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
|
@Override
|
||||||
protected void onDeviceDisconnected() {
|
protected void onDeviceDisconnected() {
|
||||||
super.onDeviceDisconnected();
|
super.onDeviceDisconnected();
|
||||||
mBodySensorLocationCharacteristic = null;
|
bodySensorLocationCharacteristic = null;
|
||||||
mHeartRateCharacteristic = null;
|
heartRateCharacteristic = null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,34 +34,37 @@ import org.achartengine.model.XYMultipleSeriesDataset;
|
|||||||
import org.achartengine.renderer.XYMultipleSeriesRenderer;
|
import org.achartengine.renderer.XYMultipleSeriesRenderer;
|
||||||
import org.achartengine.renderer.XYSeriesRenderer;
|
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
|
* 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
|
//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
|
//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
|
//XYMultipleSeriesRenderer will contain all XYSeriesRenderer and it can be used to set the properties of whole Graph
|
||||||
private XYMultipleSeriesRenderer mMultiRenderer = new XYMultipleSeriesRenderer();
|
private XYMultipleSeriesRenderer multiRenderer = new XYMultipleSeriesRenderer();
|
||||||
private static LineGraphView mInstance = null;
|
private static LineGraphView instance = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* singleton implementation of LineGraphView class
|
* Singleton implementation of LineGraphView class
|
||||||
*/
|
*/
|
||||||
public static synchronized LineGraphView getLineGraphView() {
|
@NonNull
|
||||||
if (mInstance == null) {
|
static synchronized LineGraphView getLineGraphView() {
|
||||||
mInstance = new LineGraphView();
|
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
|
* This constructor will set some properties of single chart and some properties of whole graph
|
||||||
*/
|
*/
|
||||||
public LineGraphView() {
|
private LineGraphView() {
|
||||||
//add single line chart mSeries
|
//add single line chart series
|
||||||
mDataset.addSeries(mSeries);
|
dataSet.addSeries(series);
|
||||||
|
|
||||||
//XYSeriesRenderer is used to set the properties like chart color, style of each point, etc. of single chart
|
//XYSeriesRenderer is used to set the properties like chart color, style of each point, etc. of single chart
|
||||||
final XYSeriesRenderer seriesRenderer = new XYSeriesRenderer();
|
final XYSeriesRenderer seriesRenderer = new XYSeriesRenderer();
|
||||||
@@ -71,7 +74,7 @@ public class LineGraphView {
|
|||||||
seriesRenderer.setPointStyle(PointStyle.SQUARE);
|
seriesRenderer.setPointStyle(PointStyle.SQUARE);
|
||||||
seriesRenderer.setFillPoints(true);
|
seriesRenderer.setFillPoints(true);
|
||||||
|
|
||||||
final XYMultipleSeriesRenderer renderer = mMultiRenderer;
|
final XYMultipleSeriesRenderer renderer = multiRenderer;
|
||||||
//set whole graph background color to transparent color
|
//set whole graph background color to transparent color
|
||||||
renderer.setBackgroundColor(Color.TRANSPARENT);
|
renderer.setBackgroundColor(Color.TRANSPARENT);
|
||||||
renderer.setMargins(new int[] { 50, 65, 40, 5 }); // top, left, bottom, right
|
renderer.setMargins(new int[] { 50, 65, 40, 5 }); // top, left, bottom, right
|
||||||
@@ -99,23 +102,22 @@ public class LineGraphView {
|
|||||||
/**
|
/**
|
||||||
* return graph view to activity
|
* return graph view to activity
|
||||||
*/
|
*/
|
||||||
public GraphicalView getView(Context context) {
|
GraphicalView getView(@NonNull final Context context) {
|
||||||
final GraphicalView graphView = ChartFactory.getLineChartView(context, mDataset, mMultiRenderer);
|
return ChartFactory.getLineChartView(context, dataSet, multiRenderer);
|
||||||
return graphView;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* add new x,y value to chart
|
* add new x,y value to chart
|
||||||
*/
|
*/
|
||||||
public void addValue(Point p) {
|
void addValue(@NonNull final Point p) {
|
||||||
mSeries.add(p.x, p.y);
|
series.add(p.x, p.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* clear all previous values of chart
|
* clear all previous values of chart
|
||||||
*/
|
*/
|
||||||
public void clearGraph() {
|
void clearGraph() {
|
||||||
mSeries.clear();
|
series.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ import android.content.IntentFilter;
|
|||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
@@ -50,9 +52,9 @@ public class HTSActivity extends BleProfileServiceReadyActivity<HTSService.HTSBi
|
|||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private final String TAG = "HTSActivity";
|
private final String TAG = "HTSActivity";
|
||||||
|
|
||||||
private TextView mTempValue;
|
private TextView tempValueView;
|
||||||
private TextView mUnit;
|
private TextView unitView;
|
||||||
private TextView mBatteryLevelView;
|
private TextView batteryLevelView;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreateView(final Bundle savedInstanceState) {
|
protected void onCreateView(final Bundle savedInstanceState) {
|
||||||
@@ -62,19 +64,19 @@ public class HTSActivity extends BleProfileServiceReadyActivity<HTSService.HTSBi
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onInitialize(final Bundle savedInstanceState) {
|
protected void onInitialize(final Bundle savedInstanceState) {
|
||||||
LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, makeIntentFilter());
|
LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, makeIntentFilter());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver);
|
LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setGUI() {
|
private void setGUI() {
|
||||||
mTempValue = findViewById(R.id.text_hts_value);
|
tempValueView = findViewById(R.id.text_hts_value);
|
||||||
mUnit = findViewById(R.id.text_hts_unit);
|
unitView = findViewById(R.id.text_hts_unit);
|
||||||
mBatteryLevelView = findViewById(R.id.battery);
|
batteryLevelView = findViewById(R.id.battery);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -85,8 +87,8 @@ public class HTSActivity extends BleProfileServiceReadyActivity<HTSService.HTSBi
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setDefaultUI() {
|
protected void setDefaultUI() {
|
||||||
mTempValue.setText(R.string.not_available_value);
|
tempValueView.setText(R.string.not_available_value);
|
||||||
mBatteryLevelView.setText(R.string.not_available);
|
batteryLevelView.setText(R.string.not_available);
|
||||||
|
|
||||||
setUnits();
|
setUnits();
|
||||||
}
|
}
|
||||||
@@ -97,13 +99,13 @@ public class HTSActivity extends BleProfileServiceReadyActivity<HTSService.HTSBi
|
|||||||
|
|
||||||
switch (unit) {
|
switch (unit) {
|
||||||
case SettingsFragment.SETTINGS_UNIT_C:
|
case SettingsFragment.SETTINGS_UNIT_C:
|
||||||
mUnit.setText(R.string.hts_unit_celsius);
|
this.unitView.setText(R.string.hts_unit_celsius);
|
||||||
break;
|
break;
|
||||||
case SettingsFragment.SETTINGS_UNIT_F:
|
case SettingsFragment.SETTINGS_UNIT_F:
|
||||||
mUnit.setText(R.string.hts_unit_fahrenheit);
|
this.unitView.setText(R.string.hts_unit_fahrenheit);
|
||||||
break;
|
break;
|
||||||
case SettingsFragment.SETTINGS_UNIT_K:
|
case SettingsFragment.SETTINGS_UNIT_K:
|
||||||
mUnit.setText(R.string.hts_unit_kelvin);
|
this.unitView.setText(R.string.hts_unit_kelvin);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -161,14 +163,14 @@ public class HTSActivity extends BleProfileServiceReadyActivity<HTSService.HTSBi
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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
|
// this may notify user or show some views
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceDisconnected(final BluetoothDevice device) {
|
public void onDeviceDisconnected(@NonNull final BluetoothDevice device) {
|
||||||
super.onDeviceDisconnected(device);
|
super.onDeviceDisconnected(device);
|
||||||
mBatteryLevelView.setText(R.string.not_available);
|
batteryLevelView.setText(R.string.not_available);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onTemperatureMeasurementReceived(Float value) {
|
private void onTemperatureMeasurementReceived(Float value) {
|
||||||
@@ -187,17 +189,17 @@ public class HTSActivity extends BleProfileServiceReadyActivity<HTSService.HTSBi
|
|||||||
case SettingsFragment.SETTINGS_UNIT_C:
|
case SettingsFragment.SETTINGS_UNIT_C:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
mTempValue.setText(getString(R.string.hts_value, value));
|
tempValueView.setText(getString(R.string.hts_value, value));
|
||||||
} else {
|
} else {
|
||||||
mTempValue.setText(R.string.not_available_value);
|
tempValueView.setText(R.string.not_available_value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onBatteryLevelChanged(final int 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
|
@Override
|
||||||
public void onReceive(final Context context, final Intent intent) {
|
public void onReceive(final Context context, final Intent intent) {
|
||||||
final String action = intent.getAction();
|
final String action = intent.getAction();
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ import java.util.Calendar;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import no.nordicsemi.android.ble.common.callback.ht.TemperatureMeasurementDataCallback;
|
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.ble.data.Data;
|
||||||
import no.nordicsemi.android.log.LogContract;
|
import no.nordicsemi.android.log.LogContract;
|
||||||
import no.nordicsemi.android.nrftoolbox.battery.BatteryManager;
|
import no.nordicsemi.android.nrftoolbox.battery.BatteryManager;
|
||||||
@@ -46,11 +48,11 @@ import no.nordicsemi.android.nrftoolbox.parser.TemperatureMeasurementParser;
|
|||||||
*/
|
*/
|
||||||
public class HTSManager extends BatteryManager<HTSManagerCallbacks> {
|
public class HTSManager extends BatteryManager<HTSManagerCallbacks> {
|
||||||
/** Health Thermometer service UUID */
|
/** 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 */
|
/** Health Thermometer Measurement characteristic UUID */
|
||||||
private static final UUID HT_MEASUREMENT_CHARACTERISTIC_UUID = UUID.fromString("00002A1C-0000-1000-8000-00805f9b34fb");
|
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) {
|
HTSManager(final Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
@@ -59,18 +61,18 @@ public class HTSManager extends BatteryManager<HTSManagerCallbacks> {
|
|||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
protected BatteryManagerGattCallback getGattCallback() {
|
protected BatteryManagerGattCallback getGattCallback() {
|
||||||
return mGattCallback;
|
return gattCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BluetoothGatt callbacks for connection/disconnection, service discovery,
|
* BluetoothGatt callbacks for connection/disconnection, service discovery,
|
||||||
* receiving indication, etc..
|
* receiving indication, etc..
|
||||||
*/
|
*/
|
||||||
private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() {
|
private final BatteryManagerGattCallback gattCallback = new BatteryManagerGattCallback() {
|
||||||
@Override
|
@Override
|
||||||
protected void initialize() {
|
protected void initialize() {
|
||||||
super.initialize();
|
super.initialize();
|
||||||
setIndicationCallback(mHTCharacteristic)
|
setIndicationCallback(htCharacteristic)
|
||||||
.with(new TemperatureMeasurementDataCallback() {
|
.with(new TemperatureMeasurementDataCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
|
public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
|
||||||
@@ -80,28 +82,28 @@ public class HTSManager extends BatteryManager<HTSManagerCallbacks> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTemperatureMeasurementReceived(@NonNull final BluetoothDevice device,
|
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 Calendar calendar,
|
||||||
@Nullable final Integer type) {
|
@Nullable @TemperatureType final Integer type) {
|
||||||
mCallbacks.onTemperatureMeasurementReceived(device, temperature, unit, calendar, type);
|
callbacks.onTemperatureMeasurementReceived(device, temperature, unit, calendar, type);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
enableIndications(mHTCharacteristic).enqueue();
|
enableIndications(htCharacteristic).enqueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) {
|
protected boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) {
|
||||||
final BluetoothGattService service = gatt.getService(HT_SERVICE_UUID);
|
final BluetoothGattService service = gatt.getService(HT_SERVICE_UUID);
|
||||||
if (service != null) {
|
if (service != null) {
|
||||||
mHTCharacteristic = service.getCharacteristic(HT_MEASUREMENT_CHARACTERISTIC_UUID);
|
htCharacteristic = service.getCharacteristic(HT_MEASUREMENT_CHARACTERISTIC_UUID);
|
||||||
}
|
}
|
||||||
return mHTCharacteristic != null;
|
return htCharacteristic != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDeviceDisconnected() {
|
protected void onDeviceDisconnected() {
|
||||||
super.onDeviceDisconnected();
|
super.onDeviceDisconnected();
|
||||||
mHTCharacteristic = null;
|
htCharacteristic = null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
|||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
|
||||||
import no.nordicsemi.android.ble.common.profile.ht.TemperatureMeasurementCallback;
|
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.log.Logger;
|
||||||
import no.nordicsemi.android.nrftoolbox.FeaturesActivity;
|
import no.nordicsemi.android.nrftoolbox.FeaturesActivity;
|
||||||
import no.nordicsemi.android.nrftoolbox.R;
|
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 OPEN_ACTIVITY_REQ = 0;
|
||||||
private final static int DISCONNECT_REQ = 1;
|
private final static int DISCONNECT_REQ = 1;
|
||||||
/** The last received temperature value in Celsius degrees. */
|
/** The last received temperature value in Celsius degrees. */
|
||||||
private Float mTemp;
|
private Float temp;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@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
|
* 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.
|
* @return Temperature value in Celsius.
|
||||||
*/
|
*/
|
||||||
Float getTemperature() {
|
Float getTemperature() {
|
||||||
return mTemp;
|
return temp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected LocalBinder getBinder() {
|
protected LocalBinder getBinder() {
|
||||||
return mBinder;
|
return minder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected LoggableBleManager<HTSManagerCallbacks> initializeManager() {
|
protected LoggableBleManager<HTSManagerCallbacks> initializeManager() {
|
||||||
return mManager = new HTSManager(this);
|
return manager = new HTSManager(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -98,14 +100,14 @@ public class HTSService extends BleProfileService implements HTSManagerCallbacks
|
|||||||
|
|
||||||
final IntentFilter filter = new IntentFilter();
|
final IntentFilter filter = new IntentFilter();
|
||||||
filter.addAction(ACTION_DISCONNECT);
|
filter.addAction(ACTION_DISCONNECT);
|
||||||
registerReceiver(mDisconnectActionBroadcastReceiver, filter);
|
registerReceiver(disconnectActionBroadcastReceiver, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
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
|
// when user has disconnected from the sensor, we have to cancel the notification that we've created some milliseconds before using unbindService
|
||||||
cancelNotification();
|
cancelNotification();
|
||||||
unregisterReceiver(mDisconnectActionBroadcastReceiver);
|
unregisterReceiver(disconnectActionBroadcastReceiver);
|
||||||
|
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
}
|
}
|
||||||
@@ -121,25 +123,25 @@ public class HTSService extends BleProfileService implements HTSManagerCallbacks
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceDisconnected(final BluetoothDevice device) {
|
public void onDeviceDisconnected(@NonNull final BluetoothDevice device) {
|
||||||
super.onDeviceDisconnected(device);
|
super.onDeviceDisconnected(device);
|
||||||
mTemp = null;
|
temp = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTemperatureMeasurementReceived(@NonNull final BluetoothDevice device,
|
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 Calendar calendar,
|
||||||
@Nullable final Integer type) {
|
@Nullable @TemperatureType final Integer type) {
|
||||||
mTemp = TemperatureMeasurementCallback.toCelsius(temperature, unit);
|
temp = TemperatureMeasurementCallback.toCelsius(temperature, unit);
|
||||||
|
|
||||||
final Intent broadcast = new Intent(BROADCAST_HTS_MEASUREMENT);
|
final Intent broadcast = new Intent(BROADCAST_HTS_MEASUREMENT);
|
||||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||||
broadcast.putExtra(EXTRA_TEMPERATURE, mTemp);
|
broadcast.putExtra(EXTRA_TEMPERATURE, temp);
|
||||||
// ignore the rest
|
// ignore the rest
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||||
|
|
||||||
if (!mBound) {
|
if (!bound) {
|
||||||
// Here we may update the notification to display the current temperature.
|
// Here we may update the notification to display the current temperature.
|
||||||
// TODO modify the notification here
|
// TODO modify the notification here
|
||||||
}
|
}
|
||||||
@@ -188,6 +190,7 @@ public class HTSService extends BleProfileService implements HTSManagerCallbacks
|
|||||||
* f.e. <code><string name="name">%s is connected</string></code>
|
* f.e. <code><string name="name">%s is connected</string></code>
|
||||||
* @param defaults
|
* @param defaults
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("SameParameterValue")
|
||||||
private Notification createNotification(final int messageResId, final int defaults) {
|
private Notification createNotification(final int messageResId, final int defaults) {
|
||||||
final Intent parentIntent = new Intent(this, FeaturesActivity.class);
|
final Intent parentIntent = new Intent(this, FeaturesActivity.class);
|
||||||
parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
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.
|
* 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
|
@Override
|
||||||
public void onReceive(final Context context, final Intent intent) {
|
public void onReceive(final Context context, final Intent intent) {
|
||||||
Logger.i(getLogSession(), "[Notification] Disconnect action pressed");
|
Logger.i(getLogSession(), "[Notification] Disconnect action pressed");
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import android.content.pm.PackageManager;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.appcompat.widget.Toolbar;
|
import androidx.appcompat.widget.Toolbar;
|
||||||
import android.view.Menu;
|
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";
|
private static final String SIS_DEVICE_NAME = "device_name";
|
||||||
protected static final int REQUEST_ENABLE_BT = 2;
|
protected static final int REQUEST_ENABLE_BT = 2;
|
||||||
|
|
||||||
private LoggableBleManager<? extends BleManagerCallbacks> mBleManager;
|
private LoggableBleManager<? extends BleManagerCallbacks> bleManager;
|
||||||
|
|
||||||
private TextView mDeviceNameView;
|
private TextView deviceNameView;
|
||||||
private Button mConnectButton;
|
private Button connectButton;
|
||||||
private ILogSession mLogSession;
|
private ILogSession logSession;
|
||||||
|
|
||||||
private boolean mDeviceConnected = false;
|
private boolean deviceConnected = false;
|
||||||
private String mDeviceName;
|
private String deviceName;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected final void onCreate(final Bundle savedInstanceState) {
|
protected final void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
ensureBLESupported();
|
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,
|
* 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.
|
* 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
|
// In onInitialize method a final class may register local broadcast receivers that will listen for events from the service
|
||||||
onInitialize(savedInstanceState);
|
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.
|
* 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
|
// 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)}.
|
* @param savedInstanceState contains the data it most recently supplied in {@link #onSaveInstanceState(Bundle)}.
|
||||||
* Note: <b>Otherwise it is null</b>.
|
* 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.
|
* 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)}.
|
* @param savedInstanceState contains the data it most recently supplied in {@link #onSaveInstanceState(Bundle)}.
|
||||||
* Note: <b>Otherwise it is null</b>.
|
* Note: <b>Otherwise it is null</b>.
|
||||||
*/
|
*/
|
||||||
protected void onViewCreated(final Bundle savedInstanceState) {
|
protected void onViewCreated(@Nullable final Bundle savedInstanceState) {
|
||||||
// empty default implementation
|
// empty default implementation
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,33 +131,33 @@ public abstract class BleProfileActivity extends AppCompatActivity implements Bl
|
|||||||
protected final void setUpView() {
|
protected final void setUpView() {
|
||||||
// set GUI
|
// set GUI
|
||||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||||
mConnectButton = findViewById(R.id.action_connect);
|
connectButton = findViewById(R.id.action_connect);
|
||||||
mDeviceNameView = findViewById(R.id.device_name);
|
deviceNameView = findViewById(R.id.device_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBackPressed() {
|
public void onBackPressed() {
|
||||||
mBleManager.disconnect().enqueue();
|
bleManager.disconnect().enqueue();
|
||||||
super.onBackPressed();
|
super.onBackPressed();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onSaveInstanceState(final Bundle outState) {
|
protected void onSaveInstanceState(@NonNull final Bundle outState) {
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
outState.putBoolean(SIS_CONNECTION_STATUS, mDeviceConnected);
|
outState.putBoolean(SIS_CONNECTION_STATUS, deviceConnected);
|
||||||
outState.putString(SIS_DEVICE_NAME, mDeviceName);
|
outState.putString(SIS_DEVICE_NAME, deviceName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onRestoreInstanceState(final @NonNull Bundle savedInstanceState) {
|
protected void onRestoreInstanceState(@NonNull final Bundle savedInstanceState) {
|
||||||
super.onRestoreInstanceState(savedInstanceState);
|
super.onRestoreInstanceState(savedInstanceState);
|
||||||
mDeviceConnected = savedInstanceState.getBoolean(SIS_CONNECTION_STATUS);
|
deviceConnected = savedInstanceState.getBoolean(SIS_CONNECTION_STATUS);
|
||||||
mDeviceName = savedInstanceState.getString(SIS_DEVICE_NAME);
|
deviceName = savedInstanceState.getString(SIS_DEVICE_NAME);
|
||||||
|
|
||||||
if (mDeviceConnected) {
|
if (deviceConnected) {
|
||||||
mConnectButton.setText(R.string.action_disconnect);
|
connectButton.setText(R.string.action_disconnect);
|
||||||
} else {
|
} 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
|
@Override
|
||||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
public boolean onOptionsItemSelected(@NonNull final MenuItem item) {
|
||||||
final int id = item.getItemId();
|
final int id = item.getItemId();
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case android.R.id.home:
|
case android.R.id.home:
|
||||||
@@ -199,11 +200,11 @@ public abstract class BleProfileActivity extends AppCompatActivity implements Bl
|
|||||||
*/
|
*/
|
||||||
public void onConnectClicked(final View view) {
|
public void onConnectClicked(final View view) {
|
||||||
if (isBLEEnabled()) {
|
if (isBLEEnabled()) {
|
||||||
if (!mDeviceConnected) {
|
if (!deviceConnected) {
|
||||||
setDefaultUI();
|
setDefaultUI();
|
||||||
showDeviceScanningDialog(getFilterUUID());
|
showDeviceScanningDialog(getFilterUUID());
|
||||||
} else {
|
} else {
|
||||||
mBleManager.disconnect().enqueue();
|
bleManager.disconnect().enqueue();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
showBLEDialog();
|
showBLEDialog();
|
||||||
@@ -238,18 +239,18 @@ public abstract class BleProfileActivity extends AppCompatActivity implements Bl
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceSelected(final BluetoothDevice device, final String name) {
|
public void onDeviceSelected(@NonNull final BluetoothDevice device, final String name) {
|
||||||
final int titleId = getLoggerProfileTitle();
|
final int titleId = getLoggerProfileTitle();
|
||||||
if (titleId > 0) {
|
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 nRF Logger is not installed we may want to use local logger
|
||||||
if (mLogSession == null && getLocalAuthorityLogger() != null) {
|
if (logSession == null && getLocalAuthorityLogger() != null) {
|
||||||
mLogSession = LocalLogSession.newSession(getApplicationContext(), getLocalAuthorityLogger(), device.getAddress(), name);
|
logSession = LocalLogSession.newSession(getApplicationContext(), getLocalAuthorityLogger(), device.getAddress(), name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mDeviceName = name;
|
deviceName = name;
|
||||||
mBleManager.setLogger(mLogSession);
|
bleManager.setLogger(logSession);
|
||||||
mBleManager.connect(device)
|
bleManager.connect(device)
|
||||||
.useAutoConnect(shouldAutoConnect())
|
.useAutoConnect(shouldAutoConnect())
|
||||||
.retry(3, 100)
|
.retry(3, 100)
|
||||||
.enqueue();
|
.enqueue();
|
||||||
@@ -263,35 +264,35 @@ public abstract class BleProfileActivity extends AppCompatActivity implements Bl
|
|||||||
@Override
|
@Override
|
||||||
public void onDeviceConnecting(@NonNull final BluetoothDevice device) {
|
public void onDeviceConnecting(@NonNull final BluetoothDevice device) {
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
mDeviceNameView.setText(mDeviceName != null ? mDeviceName : getString(R.string.not_available));
|
deviceNameView.setText(deviceName != null ? deviceName : getString(R.string.not_available));
|
||||||
mConnectButton.setText(R.string.action_connecting);
|
connectButton.setText(R.string.action_connecting);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceConnected(@NonNull final BluetoothDevice device) {
|
public void onDeviceConnected(@NonNull final BluetoothDevice device) {
|
||||||
mDeviceConnected = true;
|
deviceConnected = true;
|
||||||
runOnUiThread(() -> mConnectButton.setText(R.string.action_disconnect));
|
runOnUiThread(() -> connectButton.setText(R.string.action_disconnect));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceDisconnecting(@NonNull final BluetoothDevice device) {
|
public void onDeviceDisconnecting(@NonNull final BluetoothDevice device) {
|
||||||
runOnUiThread(() -> mConnectButton.setText(R.string.action_disconnecting));
|
runOnUiThread(() -> connectButton.setText(R.string.action_disconnecting));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceDisconnected(@NonNull final BluetoothDevice device) {
|
public void onDeviceDisconnected(@NonNull final BluetoothDevice device) {
|
||||||
mDeviceConnected = false;
|
deviceConnected = false;
|
||||||
mBleManager.close();
|
bleManager.close();
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
mConnectButton.setText(R.string.action_connect);
|
connectButton.setText(R.string.action_connect);
|
||||||
mDeviceNameView.setText(getDefaultDeviceName());
|
deviceNameView.setText(getDefaultDeviceName());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLinkLossOccurred(@NonNull final BluetoothDevice device) {
|
public void onLinkLossOccurred(@NonNull final BluetoothDevice device) {
|
||||||
mDeviceConnected = false;
|
deviceConnected = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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.
|
* Returns <code>true</code> if the device is connected. Services may not have been discovered yet.
|
||||||
*/
|
*/
|
||||||
protected boolean isDeviceConnected() {
|
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
|
* Returns the name of the device that the phone is currently connected to or was connected last time
|
||||||
*/
|
*/
|
||||||
protected String getDeviceName() {
|
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>
|
* @return the logger session or <code>null</code>
|
||||||
*/
|
*/
|
||||||
protected ILogSession getLogSession() {
|
protected ILogSession getLogSession() {
|
||||||
return mLogSession;
|
return logSession;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ensureBLESupported() {
|
private void ensureBLESupported() {
|
||||||
|
|||||||
@@ -58,14 +58,14 @@ public abstract class BleProfileExpandableListActivity extends ExpandableListAct
|
|||||||
private static final String SIS_DEVICE_NAME = "device_name";
|
private static final String SIS_DEVICE_NAME = "device_name";
|
||||||
protected static final int REQUEST_ENABLE_BT = 2;
|
protected static final int REQUEST_ENABLE_BT = 2;
|
||||||
|
|
||||||
private LoggableBleManager<? extends BleManagerCallbacks> mBleManager;
|
private LoggableBleManager<? extends BleManagerCallbacks> bleManager;
|
||||||
|
|
||||||
private TextView mDeviceNameView;
|
private TextView deviceNameView;
|
||||||
private Button mConnectButton;
|
private Button connectButton;
|
||||||
private ILogSession mLogSession;
|
private ILogSession logSession;
|
||||||
|
|
||||||
private boolean mDeviceConnected = false;
|
private boolean deviceConnected = false;
|
||||||
private String mDeviceName;
|
private String deviceName;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected final void onCreate(final Bundle savedInstanceState) {
|
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,
|
* 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.
|
* 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
|
// In onInitialize method a final class may register local broadcast receivers that will listen for events from the service
|
||||||
onInitialize(savedInstanceState);
|
onInitialize(savedInstanceState);
|
||||||
@@ -132,33 +132,33 @@ public abstract class BleProfileExpandableListActivity extends ExpandableListAct
|
|||||||
protected final void setUpView() {
|
protected final void setUpView() {
|
||||||
// set GUI
|
// set GUI
|
||||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||||
mConnectButton = findViewById(R.id.action_connect);
|
connectButton = findViewById(R.id.action_connect);
|
||||||
mDeviceNameView = findViewById(R.id.device_name);
|
deviceNameView = findViewById(R.id.device_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBackPressed() {
|
public void onBackPressed() {
|
||||||
mBleManager.disconnect().enqueue();
|
bleManager.disconnect().enqueue();
|
||||||
super.onBackPressed();
|
super.onBackPressed();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onSaveInstanceState(final Bundle outState) {
|
protected void onSaveInstanceState(final Bundle outState) {
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
outState.putBoolean(SIS_CONNECTION_STATUS, mDeviceConnected);
|
outState.putBoolean(SIS_CONNECTION_STATUS, deviceConnected);
|
||||||
outState.putString(SIS_DEVICE_NAME, mDeviceName);
|
outState.putString(SIS_DEVICE_NAME, deviceName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onRestoreInstanceState(final @NonNull Bundle savedInstanceState) {
|
protected void onRestoreInstanceState(final @NonNull Bundle savedInstanceState) {
|
||||||
super.onRestoreInstanceState(savedInstanceState);
|
super.onRestoreInstanceState(savedInstanceState);
|
||||||
mDeviceConnected = savedInstanceState.getBoolean(SIS_CONNECTION_STATUS);
|
deviceConnected = savedInstanceState.getBoolean(SIS_CONNECTION_STATUS);
|
||||||
mDeviceName = savedInstanceState.getString(SIS_DEVICE_NAME);
|
deviceName = savedInstanceState.getString(SIS_DEVICE_NAME);
|
||||||
|
|
||||||
if (mDeviceConnected) {
|
if (deviceConnected) {
|
||||||
mConnectButton.setText(R.string.action_disconnect);
|
connectButton.setText(R.string.action_disconnect);
|
||||||
} else {
|
} 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) {
|
public void onConnectClicked(final View view) {
|
||||||
if (isBLEEnabled()) {
|
if (isBLEEnabled()) {
|
||||||
if (!mDeviceConnected) {
|
if (!deviceConnected) {
|
||||||
setDefaultUI();
|
setDefaultUI();
|
||||||
showDeviceScanningDialog(getFilterUUID());
|
showDeviceScanningDialog(getFilterUUID());
|
||||||
} else {
|
} else {
|
||||||
mBleManager.disconnect().enqueue();
|
bleManager.disconnect().enqueue();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
showBLEDialog();
|
showBLEDialog();
|
||||||
@@ -241,18 +241,18 @@ public abstract class BleProfileExpandableListActivity extends ExpandableListAct
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceSelected(final BluetoothDevice device, final String name) {
|
public void onDeviceSelected(@NonNull final BluetoothDevice device, final String name) {
|
||||||
final int titleId = getLoggerProfileTitle();
|
final int titleId = getLoggerProfileTitle();
|
||||||
if (titleId > 0) {
|
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 nRF Logger is not installed we may want to use local logger
|
||||||
if (mLogSession == null && getLocalAuthorityLogger() != null) {
|
if (logSession == null && getLocalAuthorityLogger() != null) {
|
||||||
mLogSession = LocalLogSession.newSession(getApplicationContext(), getLocalAuthorityLogger(), device.getAddress(), name);
|
logSession = LocalLogSession.newSession(getApplicationContext(), getLocalAuthorityLogger(), device.getAddress(), name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mDeviceName = name;
|
deviceName = name;
|
||||||
mBleManager.setLogger(mLogSession);
|
bleManager.setLogger(logSession);
|
||||||
mBleManager.connect(device)
|
bleManager.connect(device)
|
||||||
.useAutoConnect(shouldAutoConnect())
|
.useAutoConnect(shouldAutoConnect())
|
||||||
.retry(3, 100)
|
.retry(3, 100)
|
||||||
.enqueue();
|
.enqueue();
|
||||||
@@ -266,35 +266,35 @@ public abstract class BleProfileExpandableListActivity extends ExpandableListAct
|
|||||||
@Override
|
@Override
|
||||||
public void onDeviceConnecting(@NonNull final BluetoothDevice device) {
|
public void onDeviceConnecting(@NonNull final BluetoothDevice device) {
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
mDeviceNameView.setText(mDeviceName != null ? mDeviceName : getString(R.string.not_available));
|
deviceNameView.setText(deviceName != null ? deviceName : getString(R.string.not_available));
|
||||||
mConnectButton.setText(R.string.action_connecting);
|
connectButton.setText(R.string.action_connecting);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceConnected(@NonNull final BluetoothDevice device) {
|
public void onDeviceConnected(@NonNull final BluetoothDevice device) {
|
||||||
mDeviceConnected = true;
|
deviceConnected = true;
|
||||||
runOnUiThread(() -> mConnectButton.setText(R.string.action_disconnect));
|
runOnUiThread(() -> connectButton.setText(R.string.action_disconnect));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceDisconnecting(@NonNull final BluetoothDevice device) {
|
public void onDeviceDisconnecting(@NonNull final BluetoothDevice device) {
|
||||||
runOnUiThread(() -> mConnectButton.setText(R.string.action_disconnecting));
|
runOnUiThread(() -> connectButton.setText(R.string.action_disconnecting));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceDisconnected(@NonNull final BluetoothDevice device) {
|
public void onDeviceDisconnected(@NonNull final BluetoothDevice device) {
|
||||||
mDeviceConnected = false;
|
deviceConnected = false;
|
||||||
mBleManager.close();
|
bleManager.close();
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
mConnectButton.setText(R.string.action_connect);
|
connectButton.setText(R.string.action_connect);
|
||||||
mDeviceNameView.setText(getDefaultDeviceName());
|
deviceNameView.setText(getDefaultDeviceName());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLinkLossOccurred(@NonNull final BluetoothDevice device) {
|
public void onLinkLossOccurred(@NonNull final BluetoothDevice device) {
|
||||||
mDeviceConnected = false;
|
deviceConnected = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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.
|
* Returns <code>true</code> if the device is connected. Services may not have been discovered yet.
|
||||||
*/
|
*/
|
||||||
protected boolean isDeviceConnected() {
|
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
|
* Returns the name of the device that the phone is currently connected to or was connected last time
|
||||||
*/
|
*/
|
||||||
protected String getDeviceName() {
|
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>
|
* @return the logger session or <code>null</code>
|
||||||
*/
|
*/
|
||||||
protected ILogSession getLogSession() {
|
protected ILogSession getLogSession() {
|
||||||
return mLogSession;
|
return logSession;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ensureBLESupported() {
|
private void ensureBLESupported() {
|
||||||
|
|||||||
@@ -83,16 +83,16 @@ public abstract class BleProfileService extends Service implements BleManagerCal
|
|||||||
public static final int STATE_CONNECTING = 2;
|
public static final int STATE_CONNECTING = 2;
|
||||||
public static final int STATE_DISCONNECTING = 3;
|
public static final int STATE_DISCONNECTING = 3;
|
||||||
|
|
||||||
private LoggableBleManager<BleManagerCallbacks> mBleManager;
|
private LoggableBleManager<BleManagerCallbacks> bleManager;
|
||||||
private Handler mHandler;
|
private Handler handler;
|
||||||
|
|
||||||
protected boolean mBound;
|
protected boolean bound;
|
||||||
private boolean mActivityIsChangingConfiguration;
|
private boolean activityIsChangingConfiguration;
|
||||||
private BluetoothDevice mBluetoothDevice;
|
private BluetoothDevice bluetoothDevice;
|
||||||
private String mDeviceName;
|
private String deviceName;
|
||||||
private ILogSession mLogSession;
|
private ILogSession logSession;
|
||||||
|
|
||||||
private final BroadcastReceiver mBluetoothStateBroadcastReceiver = new BroadcastReceiver() {
|
private final BroadcastReceiver bluetoothStateBroadcastReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(final Context context, final Intent intent) {
|
public void onReceive(final Context context, final Intent intent) {
|
||||||
final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF);
|
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.
|
* Disconnects from the sensor.
|
||||||
*/
|
*/
|
||||||
public final void disconnect() {
|
public final void disconnect() {
|
||||||
final int state = mBleManager.getConnectionState();
|
final int state = bleManager.getConnectionState();
|
||||||
if (state == BluetoothGatt.STATE_DISCONNECTED || state == BluetoothGatt.STATE_DISCONNECTING) {
|
if (state == BluetoothGatt.STATE_DISCONNECTED || state == BluetoothGatt.STATE_DISCONNECTING) {
|
||||||
mBleManager.close();
|
bleManager.close();
|
||||||
onDeviceDisconnected(mBluetoothDevice);
|
onDeviceDisconnected(bluetoothDevice);
|
||||||
return;
|
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
|
* @param changing true if the bound activity is finishing
|
||||||
*/
|
*/
|
||||||
public void setActivityIsChangingConfiguration(final boolean changing) {
|
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
|
* @return device address
|
||||||
*/
|
*/
|
||||||
public String getDeviceAddress() {
|
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
|
* @return the device name
|
||||||
*/
|
*/
|
||||||
public String getDeviceName() {
|
public String getDeviceName() {
|
||||||
return mDeviceName;
|
return deviceName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -177,7 +177,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
|
|||||||
* @return the Bluetooth device
|
* @return the Bluetooth device
|
||||||
*/
|
*/
|
||||||
public BluetoothDevice getBluetoothDevice() {
|
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
|
* @return <code>true</code> if device is connected to the sensor, <code>false</code> otherwise
|
||||||
*/
|
*/
|
||||||
public boolean isConnected() {
|
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()}.
|
* @return the connection state, as in {@link BleManager#getConnectionState()}.
|
||||||
*/
|
*/
|
||||||
public int 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
|
* @return the log session
|
||||||
*/
|
*/
|
||||||
public ILogSession getLogSession() {
|
public ILogSession getLogSession() {
|
||||||
return mLogSession;
|
return logSession;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void log(final int level, @NonNull final String message) {
|
public void log(final int level, @NonNull final String message) {
|
||||||
Logger.log(mLogSession, level, message);
|
Logger.log(logSession, level, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void log(final int level, final @StringRes int messageRes, final Object... params) {
|
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.
|
* The handler may be used to postpone execution of some operations or to run them in UI thread.
|
||||||
*/
|
*/
|
||||||
protected Handler getHandler() {
|
protected Handler getHandler() {
|
||||||
return mHandler;
|
return handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -241,15 +241,15 @@ public abstract class BleProfileService extends Service implements BleManagerCal
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBinder onBind(final Intent intent) {
|
public IBinder onBind(final Intent intent) {
|
||||||
mBound = true;
|
bound = true;
|
||||||
return getBinder();
|
return getBinder();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void onRebind(final Intent intent) {
|
public final void onRebind(final Intent intent) {
|
||||||
mBound = true;
|
bound = true;
|
||||||
|
|
||||||
if (!mActivityIsChangingConfiguration)
|
if (!activityIsChangingConfiguration)
|
||||||
onRebind();
|
onRebind();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,9 +264,9 @@ public abstract class BleProfileService extends Service implements BleManagerCal
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final boolean onUnbind(final Intent intent) {
|
public final boolean onUnbind(final Intent intent) {
|
||||||
mBound = false;
|
bound = false;
|
||||||
|
|
||||||
if (!mActivityIsChangingConfiguration)
|
if (!activityIsChangingConfiguration)
|
||||||
onUnbind();
|
onUnbind();
|
||||||
|
|
||||||
// We want the onRebind method be called if anything else binds to it again
|
// 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() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
|
|
||||||
mHandler = new Handler();
|
handler = new Handler();
|
||||||
|
|
||||||
// Initialize the manager
|
// Initialize the manager
|
||||||
mBleManager = initializeManager();
|
bleManager = initializeManager();
|
||||||
mBleManager.setGattCallbacks(this);
|
bleManager.setGattCallbacks(this);
|
||||||
|
|
||||||
// Register broadcast receivers
|
// Register broadcast receivers
|
||||||
registerReceiver(mBluetoothStateBroadcastReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
|
registerReceiver(bluetoothStateBroadcastReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
|
||||||
|
|
||||||
// Service has now been created
|
// Service has now been created
|
||||||
onServiceCreated();
|
onServiceCreated();
|
||||||
@@ -335,18 +335,18 @@ public abstract class BleProfileService extends Service implements BleManagerCal
|
|||||||
throw new UnsupportedOperationException("No device address at EXTRA_DEVICE_ADDRESS key");
|
throw new UnsupportedOperationException("No device address at EXTRA_DEVICE_ADDRESS key");
|
||||||
|
|
||||||
final Uri logUri = intent.getParcelableExtra(EXTRA_LOG_URI);
|
final Uri logUri = intent.getParcelableExtra(EXTRA_LOG_URI);
|
||||||
mLogSession = Logger.openSession(getApplicationContext(), logUri);
|
logSession = Logger.openSession(getApplicationContext(), logUri);
|
||||||
mDeviceName = intent.getStringExtra(EXTRA_DEVICE_NAME);
|
deviceName = intent.getStringExtra(EXTRA_DEVICE_NAME);
|
||||||
|
|
||||||
Logger.i(mLogSession, "Service started");
|
Logger.i(logSession, "Service started");
|
||||||
|
|
||||||
final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
|
final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
|
||||||
final String deviceAddress = intent.getStringExtra(EXTRA_DEVICE_ADDRESS);
|
final String deviceAddress = intent.getStringExtra(EXTRA_DEVICE_ADDRESS);
|
||||||
mBluetoothDevice = adapter.getRemoteDevice(deviceAddress);
|
bluetoothDevice = adapter.getRemoteDevice(deviceAddress);
|
||||||
|
|
||||||
mBleManager.setLogger(mLogSession);
|
bleManager.setLogger(logSession);
|
||||||
onServiceStarted();
|
onServiceStarted();
|
||||||
mBleManager.connect(mBluetoothDevice)
|
bleManager.connect(bluetoothDevice)
|
||||||
.useAutoConnect(shouldAutoConnect())
|
.useAutoConnect(shouldAutoConnect())
|
||||||
.retry(3, 100)
|
.retry(3, 100)
|
||||||
.enqueue();
|
.enqueue();
|
||||||
@@ -374,16 +374,16 @@ public abstract class BleProfileService extends Service implements BleManagerCal
|
|||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
// Unregister broadcast receivers
|
// Unregister broadcast receivers
|
||||||
unregisterReceiver(mBluetoothStateBroadcastReceiver);
|
unregisterReceiver(bluetoothStateBroadcastReceiver);
|
||||||
|
|
||||||
// shutdown the manager
|
// shutdown the manager
|
||||||
mBleManager.close();
|
bleManager.close();
|
||||||
Logger.i(mLogSession, "Service destroyed");
|
Logger.i(logSession, "Service destroyed");
|
||||||
mBleManager = null;
|
bleManager = null;
|
||||||
mBluetoothDevice = null;
|
bluetoothDevice = null;
|
||||||
mDeviceName = null;
|
deviceName = null;
|
||||||
mLogSession = null;
|
logSession = null;
|
||||||
mHandler = null;
|
handler = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -405,7 +405,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
|
|||||||
@Override
|
@Override
|
||||||
public void onDeviceConnecting(@NonNull final BluetoothDevice device) {
|
public void onDeviceConnecting(@NonNull final BluetoothDevice device) {
|
||||||
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
|
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);
|
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_CONNECTING);
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||||
}
|
}
|
||||||
@@ -414,8 +414,8 @@ public abstract class BleProfileService extends Service implements BleManagerCal
|
|||||||
public void onDeviceConnected(@NonNull final BluetoothDevice device) {
|
public void onDeviceConnected(@NonNull final BluetoothDevice device) {
|
||||||
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
|
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
|
||||||
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_CONNECTED);
|
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_CONNECTED);
|
||||||
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
|
broadcast.putExtra(EXTRA_DEVICE, bluetoothDevice);
|
||||||
broadcast.putExtra(EXTRA_DEVICE_NAME, mDeviceName);
|
broadcast.putExtra(EXTRA_DEVICE_NAME, deviceName);
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -423,7 +423,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
|
|||||||
public void onDeviceDisconnecting(@NonNull final BluetoothDevice device) {
|
public void onDeviceDisconnecting(@NonNull final BluetoothDevice device) {
|
||||||
// Notify user about changing the state to DISCONNECTING
|
// Notify user about changing the state to DISCONNECTING
|
||||||
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
|
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);
|
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_DISCONNECTING);
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
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.
|
// disconnects due to a link loss, the onLinkLossOccurred(BluetoothDevice) method will be called instead.
|
||||||
|
|
||||||
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
|
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);
|
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_DISCONNECTED);
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||||
|
|
||||||
@@ -457,14 +457,14 @@ public abstract class BleProfileService extends Service implements BleManagerCal
|
|||||||
|
|
||||||
protected void stopService() {
|
protected void stopService() {
|
||||||
// user requested disconnection. We must stop the service
|
// user requested disconnection. We must stop the service
|
||||||
Logger.v(mLogSession, "Stopping service...");
|
Logger.v(logSession, "Stopping service...");
|
||||||
stopSelf();
|
stopSelf();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLinkLossOccurred(@NonNull final BluetoothDevice device) {
|
public void onLinkLossOccurred(@NonNull final BluetoothDevice device) {
|
||||||
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
|
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);
|
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_LINK_LOSS);
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||||
}
|
}
|
||||||
@@ -472,7 +472,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
|
|||||||
@Override
|
@Override
|
||||||
public void onServicesDiscovered(@NonNull final BluetoothDevice device, final boolean optionalServicesFound) {
|
public void onServicesDiscovered(@NonNull final BluetoothDevice device, final boolean optionalServicesFound) {
|
||||||
final Intent broadcast = new Intent(BROADCAST_SERVICES_DISCOVERED);
|
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_PRIMARY, true);
|
||||||
broadcast.putExtra(EXTRA_SERVICE_SECONDARY, optionalServicesFound);
|
broadcast.putExtra(EXTRA_SERVICE_SECONDARY, optionalServicesFound);
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||||
@@ -481,14 +481,14 @@ public abstract class BleProfileService extends Service implements BleManagerCal
|
|||||||
@Override
|
@Override
|
||||||
public void onDeviceReady(@NonNull final BluetoothDevice device) {
|
public void onDeviceReady(@NonNull final BluetoothDevice device) {
|
||||||
final Intent broadcast = new Intent(BROADCAST_DEVICE_READY);
|
final Intent broadcast = new Intent(BROADCAST_DEVICE_READY);
|
||||||
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
|
broadcast.putExtra(EXTRA_DEVICE, bluetoothDevice);
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceNotSupported(@NonNull final BluetoothDevice device) {
|
public void onDeviceNotSupported(@NonNull final BluetoothDevice device) {
|
||||||
final Intent broadcast = new Intent(BROADCAST_SERVICES_DISCOVERED);
|
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_PRIMARY, false);
|
||||||
broadcast.putExtra(EXTRA_SERVICE_SECONDARY, false);
|
broadcast.putExtra(EXTRA_SERVICE_SECONDARY, false);
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||||
@@ -499,7 +499,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
|
|||||||
@Override
|
@Override
|
||||||
public void onBatteryValueReceived(@NonNull final BluetoothDevice device, final int value) {
|
public void onBatteryValueReceived(@NonNull final BluetoothDevice device, final int value) {
|
||||||
final Intent broadcast = new Intent(BROADCAST_BATTERY_LEVEL);
|
final Intent broadcast = new Intent(BROADCAST_BATTERY_LEVEL);
|
||||||
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
|
broadcast.putExtra(EXTRA_DEVICE, bluetoothDevice);
|
||||||
broadcast.putExtra(EXTRA_BATTERY_LEVEL, value);
|
broadcast.putExtra(EXTRA_BATTERY_LEVEL, value);
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
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);
|
showToast(no.nordicsemi.android.nrftoolbox.common.R.string.bonding);
|
||||||
|
|
||||||
final Intent broadcast = new Intent(BROADCAST_BOND_STATE);
|
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);
|
broadcast.putExtra(EXTRA_BOND_STATE, BluetoothDevice.BOND_BONDING);
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
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);
|
showToast(no.nordicsemi.android.nrftoolbox.common.R.string.bonded);
|
||||||
|
|
||||||
final Intent broadcast = new Intent(BROADCAST_BOND_STATE);
|
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);
|
broadcast.putExtra(EXTRA_BOND_STATE, BluetoothDevice.BOND_BONDED);
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
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);
|
showToast(no.nordicsemi.android.nrftoolbox.common.R.string.bonding_failed);
|
||||||
|
|
||||||
final Intent broadcast = new Intent(BROADCAST_BOND_STATE);
|
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);
|
broadcast.putExtra(EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||||
}
|
}
|
||||||
@@ -537,7 +537,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
|
|||||||
@Override
|
@Override
|
||||||
public void onError(@NonNull final BluetoothDevice device, @NonNull 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);
|
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_MESSAGE, message);
|
||||||
broadcast.putExtra(EXTRA_ERROR_CODE, errorCode);
|
broadcast.putExtra(EXTRA_ERROR_CODE, errorCode);
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
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
|
* @param messageResId an resource id of the message to be shown
|
||||||
*/
|
*/
|
||||||
protected void showToast(final int messageResId) {
|
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
|
* @param message a message to be shown
|
||||||
*/
|
*/
|
||||||
protected void showToast(final String message) {
|
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
|
* @return the log session
|
||||||
*/
|
*/
|
||||||
protected ILogSession getLogSession() {
|
protected ILogSession getLogSession() {
|
||||||
return mLogSession;
|
return logSession;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -577,7 +577,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
|
|||||||
* @return device address
|
* @return device address
|
||||||
*/
|
*/
|
||||||
protected String getDeviceAddress() {
|
protected String getDeviceAddress() {
|
||||||
return mBluetoothDevice.getAddress();
|
return bluetoothDevice.getAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -586,7 +586,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
|
|||||||
* @return bluetooth device
|
* @return bluetooth device
|
||||||
*/
|
*/
|
||||||
protected BluetoothDevice getBluetoothDevice() {
|
protected BluetoothDevice getBluetoothDevice() {
|
||||||
return mBluetoothDevice;
|
return bluetoothDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -595,7 +595,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
|
|||||||
* @return the device name
|
* @return the device name
|
||||||
*/
|
*/
|
||||||
protected String getDeviceName() {
|
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
|
* @return <code>true</code> if device is connected to the sensor, <code>false</code> otherwise
|
||||||
*/
|
*/
|
||||||
protected boolean isConnected() {
|
protected boolean isConnected() {
|
||||||
return mBleManager != null && mBleManager.isConnected();
|
return bleManager != null && bleManager.isConnected();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,16 +79,16 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
|
|||||||
private static final String LOG_URI = "log_uri";
|
private static final String LOG_URI = "log_uri";
|
||||||
protected static final int REQUEST_ENABLE_BT = 2;
|
protected static final int REQUEST_ENABLE_BT = 2;
|
||||||
|
|
||||||
private E mService;
|
private E service;
|
||||||
|
|
||||||
private TextView mDeviceNameView;
|
private TextView deviceNameView;
|
||||||
private Button mConnectButton;
|
private Button connectButton;
|
||||||
|
|
||||||
private ILogSession mLogSession;
|
private ILogSession logSession;
|
||||||
private BluetoothDevice mBluetoothDevice;
|
private BluetoothDevice bluetoothDevice;
|
||||||
private String mDeviceName;
|
private String deviceName;
|
||||||
|
|
||||||
private final BroadcastReceiver mCommonBroadcastReceiver = new BroadcastReceiver() {
|
private final BroadcastReceiver commonBroadcastReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(final Context context, final Intent intent) {
|
public void onReceive(final Context context, final Intent intent) {
|
||||||
// Check if the broadcast applies the connected device
|
// Check if the broadcast applies the connected device
|
||||||
@@ -96,6 +96,9 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
final BluetoothDevice bluetoothDevice = intent.getParcelableExtra(BleProfileService.EXTRA_DEVICE);
|
final BluetoothDevice bluetoothDevice = intent.getParcelableExtra(BleProfileService.EXTRA_DEVICE);
|
||||||
|
if (bluetoothDevice == null)
|
||||||
|
return;
|
||||||
|
|
||||||
final String action = intent.getAction();
|
final String action = intent.getAction();
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case BleProfileService.BROADCAST_CONNECTION_STATE: {
|
case BleProfileService.BROADCAST_CONNECTION_STATE: {
|
||||||
@@ -103,13 +106,13 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
|
|||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case BleProfileService.STATE_CONNECTED: {
|
case BleProfileService.STATE_CONNECTED: {
|
||||||
mDeviceName = intent.getStringExtra(BleProfileService.EXTRA_DEVICE_NAME);
|
deviceName = intent.getStringExtra(BleProfileService.EXTRA_DEVICE_NAME);
|
||||||
onDeviceConnected(bluetoothDevice);
|
onDeviceConnected(bluetoothDevice);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BleProfileService.STATE_DISCONNECTED: {
|
case BleProfileService.STATE_DISCONNECTED: {
|
||||||
onDeviceDisconnected(bluetoothDevice);
|
onDeviceDisconnected(bluetoothDevice);
|
||||||
mDeviceName = null;
|
deviceName = null;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BleProfileService.STATE_LINK_LOSS: {
|
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")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public void onServiceConnected(final ComponentName name, final IBinder service) {
|
public void onServiceConnected(final ComponentName name, final IBinder service) {
|
||||||
final E bleService = mService = (E) service;
|
final E bleService = BleProfileServiceReadyActivity.this.service = (E) service;
|
||||||
mBluetoothDevice = bleService.getBluetoothDevice();
|
bluetoothDevice = bleService.getBluetoothDevice();
|
||||||
mLogSession = mService.getLogSession();
|
logSession = bleService.getLogSession();
|
||||||
Logger.d(mLogSession, "Activity bound to the service");
|
Logger.d(logSession, "Activity bound to the service");
|
||||||
onServiceBound(bleService);
|
onServiceBound(bleService);
|
||||||
|
|
||||||
// Update UI
|
// Update UI
|
||||||
mDeviceName = bleService.getDeviceName();
|
deviceName = bleService.getDeviceName();
|
||||||
mDeviceNameView.setText(mDeviceName);
|
deviceNameView.setText(deviceName);
|
||||||
mConnectButton.setText(R.string.action_disconnect);
|
connectButton.setText(R.string.action_disconnect);
|
||||||
|
|
||||||
// And notify user if device is connected
|
// And notify user if device is connected
|
||||||
if (bleService.isConnected()) {
|
if (bleService.isConnected()) {
|
||||||
onDeviceConnected(mBluetoothDevice);
|
onDeviceConnected(bluetoothDevice);
|
||||||
} else {
|
} else {
|
||||||
// If the device is not connected it means that either it is still connecting,
|
// 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).
|
// 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.
|
// 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
|
// It will be called only when there is critically low memory, in practice never
|
||||||
// when the activity is in foreground.
|
// when the activity is in foreground.
|
||||||
Logger.d(mLogSession, "Activity disconnected from the service");
|
Logger.d(logSession, "Activity disconnected from the service");
|
||||||
mDeviceNameView.setText(getDefaultDeviceName());
|
deviceNameView.setText(getDefaultDeviceName());
|
||||||
mConnectButton.setText(R.string.action_connect);
|
connectButton.setText(R.string.action_connect);
|
||||||
|
|
||||||
mService = null;
|
service = null;
|
||||||
mDeviceName = null;
|
deviceName = null;
|
||||||
mBluetoothDevice = null;
|
bluetoothDevice = null;
|
||||||
mLogSession = null;
|
logSession = null;
|
||||||
onServiceUnbound();
|
onServiceUnbound();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -222,7 +225,7 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
|
|||||||
// Restore the old log session
|
// Restore the old log session
|
||||||
if (savedInstanceState != null) {
|
if (savedInstanceState != null) {
|
||||||
final Uri logUri = savedInstanceState.getParcelable(LOG_URI);
|
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
|
// 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
|
// View is ready to be used
|
||||||
onViewCreated(savedInstanceState);
|
onViewCreated(savedInstanceState);
|
||||||
|
|
||||||
LocalBroadcastManager.getInstance(this).registerReceiver(mCommonBroadcastReceiver, makeIntentFilter());
|
LocalBroadcastManager.getInstance(this).registerReceiver(commonBroadcastReceiver, makeIntentFilter());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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.
|
* 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());
|
final Intent service = new Intent(this, getServiceClass());
|
||||||
// We pass 0 as a flag so the service will not be created if not exists.
|
// 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
|
* 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
|
* 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.
|
* 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
|
// 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
|
// disappear, we may want to disable some device features to reduce the battery
|
||||||
// consumption.
|
// consumption.
|
||||||
if (mService != null)
|
if (service != null)
|
||||||
mService.setActivityIsChangingConfiguration(isChangingConfigurations());
|
service.setActivityIsChangingConfiguration(isChangingConfigurations());
|
||||||
|
|
||||||
unbindService(mServiceConnection);
|
unbindService(serviceConnection);
|
||||||
mService = null;
|
service = null;
|
||||||
|
|
||||||
Logger.d(mLogSession, "Activity unbound from the service");
|
Logger.d(logSession, "Activity unbound from the service");
|
||||||
onServiceUnbound();
|
onServiceUnbound();
|
||||||
mDeviceName = null;
|
deviceName = null;
|
||||||
mBluetoothDevice = null;
|
bluetoothDevice = null;
|
||||||
mLogSession = null;
|
logSession = null;
|
||||||
} catch (final IllegalArgumentException e) {
|
} catch (final IllegalArgumentException e) {
|
||||||
// do nothing, we were not connected to the sensor
|
// do nothing, we were not connected to the sensor
|
||||||
}
|
}
|
||||||
@@ -290,7 +293,7 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
|
|||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
|
|
||||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(mCommonBroadcastReceiver);
|
LocalBroadcastManager.getInstance(this).unregisterReceiver(commonBroadcastReceiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IntentFilter makeIntentFilter() {
|
private static IntentFilter makeIntentFilter() {
|
||||||
@@ -329,7 +332,7 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
|
|||||||
* @return the service binder or <code>null</code>
|
* @return the service binder or <code>null</code>
|
||||||
*/
|
*/
|
||||||
protected E getService() {
|
protected E getService() {
|
||||||
return mService;
|
return service;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -364,24 +367,24 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
|
|||||||
protected final void setUpView() {
|
protected final void setUpView() {
|
||||||
// set GUI
|
// set GUI
|
||||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||||
mConnectButton = findViewById(R.id.action_connect);
|
connectButton = findViewById(R.id.action_connect);
|
||||||
mDeviceNameView = findViewById(R.id.device_name);
|
deviceNameView = findViewById(R.id.device_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onSaveInstanceState(final Bundle outState) {
|
protected void onSaveInstanceState(@NonNull final Bundle outState) {
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
outState.putString(SIS_DEVICE_NAME, mDeviceName);
|
outState.putString(SIS_DEVICE_NAME, deviceName);
|
||||||
outState.putParcelable(SIS_DEVICE, mBluetoothDevice);
|
outState.putParcelable(SIS_DEVICE, bluetoothDevice);
|
||||||
if (mLogSession != null)
|
if (logSession != null)
|
||||||
outState.putParcelable(LOG_URI, mLogSession.getSessionUri());
|
outState.putParcelable(LOG_URI, logSession.getSessionUri());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onRestoreInstanceState(final @NonNull Bundle savedInstanceState) {
|
protected void onRestoreInstanceState(final @NonNull Bundle savedInstanceState) {
|
||||||
super.onRestoreInstanceState(savedInstanceState);
|
super.onRestoreInstanceState(savedInstanceState);
|
||||||
mDeviceName = savedInstanceState.getString(SIS_DEVICE_NAME);
|
deviceName = savedInstanceState.getString(SIS_DEVICE_NAME);
|
||||||
mBluetoothDevice = savedInstanceState.getParcelable(SIS_DEVICE);
|
bluetoothDevice = savedInstanceState.getParcelable(SIS_DEVICE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -423,11 +426,11 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
|
|||||||
*/
|
*/
|
||||||
public void onConnectClicked(final View view) {
|
public void onConnectClicked(final View view) {
|
||||||
if (isBLEEnabled()) {
|
if (isBLEEnabled()) {
|
||||||
if (mService == null) {
|
if (service == null) {
|
||||||
setDefaultUI();
|
setDefaultUI();
|
||||||
showDeviceScanningDialog(getFilterUUID());
|
showDeviceScanningDialog(getFilterUUID());
|
||||||
} else {
|
} else {
|
||||||
mService.disconnect();
|
service.disconnect();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
showBLEDialog();
|
showBLEDialog();
|
||||||
@@ -453,28 +456,28 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceSelected(final BluetoothDevice device, final String name) {
|
public void onDeviceSelected(@NonNull final BluetoothDevice device, final String name) {
|
||||||
final int titleId = getLoggerProfileTitle();
|
final int titleId = getLoggerProfileTitle();
|
||||||
if (titleId > 0) {
|
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 nRF Logger is not installed we may want to use local logger
|
||||||
if (mLogSession == null && getLocalAuthorityLogger() != null) {
|
if (logSession == null && getLocalAuthorityLogger() != null) {
|
||||||
mLogSession = LocalLogSession.newSession(getApplicationContext(), getLocalAuthorityLogger(), device.getAddress(), name);
|
logSession = LocalLogSession.newSession(getApplicationContext(), getLocalAuthorityLogger(), device.getAddress(), name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mBluetoothDevice = device;
|
bluetoothDevice = device;
|
||||||
mDeviceName = name;
|
deviceName = name;
|
||||||
|
|
||||||
// The device may not be in the range but the service will try to connect to it if it reach it
|
// 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());
|
final Intent service = new Intent(this, getServiceClass());
|
||||||
service.putExtra(BleProfileService.EXTRA_DEVICE_ADDRESS, device.getAddress());
|
service.putExtra(BleProfileService.EXTRA_DEVICE_ADDRESS, device.getAddress());
|
||||||
service.putExtra(BleProfileService.EXTRA_DEVICE_NAME, name);
|
service.putExtra(BleProfileService.EXTRA_DEVICE_NAME, name);
|
||||||
if (mLogSession != null)
|
if (logSession != null)
|
||||||
service.putExtra(BleProfileService.EXTRA_LOG_URI, mLogSession.getSessionUri());
|
service.putExtra(BleProfileService.EXTRA_LOG_URI, logSession.getSessionUri());
|
||||||
startService(service);
|
startService(service);
|
||||||
Logger.d(mLogSession, "Binding to the service...");
|
Logger.d(logSession, "Binding to the service...");
|
||||||
bindService(service, mServiceConnection, 0);
|
bindService(service, serviceConnection, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -483,80 +486,80 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceConnecting(final BluetoothDevice device) {
|
public void onDeviceConnecting(@NonNull final BluetoothDevice device) {
|
||||||
mDeviceNameView.setText(mDeviceName != null ? mDeviceName : getString(R.string.not_available));
|
deviceNameView.setText(deviceName != null ? deviceName : getString(R.string.not_available));
|
||||||
mConnectButton.setText(R.string.action_connecting);
|
connectButton.setText(R.string.action_connecting);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceConnected(final BluetoothDevice device) {
|
public void onDeviceConnected(@NonNull final BluetoothDevice device) {
|
||||||
mDeviceNameView.setText(mDeviceName);
|
deviceNameView.setText(deviceName);
|
||||||
mConnectButton.setText(R.string.action_disconnect);
|
connectButton.setText(R.string.action_disconnect);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceDisconnecting(final BluetoothDevice device) {
|
public void onDeviceDisconnecting(@NonNull final BluetoothDevice device) {
|
||||||
mConnectButton.setText(R.string.action_disconnecting);
|
connectButton.setText(R.string.action_disconnecting);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceDisconnected(final BluetoothDevice device) {
|
public void onDeviceDisconnected(@NonNull final BluetoothDevice device) {
|
||||||
mConnectButton.setText(R.string.action_connect);
|
connectButton.setText(R.string.action_connect);
|
||||||
mDeviceNameView.setText(getDefaultDeviceName());
|
deviceNameView.setText(getDefaultDeviceName());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Logger.d(mLogSession, "Unbinding from the service...");
|
Logger.d(logSession, "Unbinding from the service...");
|
||||||
unbindService(mServiceConnection);
|
unbindService(serviceConnection);
|
||||||
mService = null;
|
service = null;
|
||||||
|
|
||||||
Logger.d(mLogSession, "Activity unbound from the service");
|
Logger.d(logSession, "Activity unbound from the service");
|
||||||
onServiceUnbound();
|
onServiceUnbound();
|
||||||
mDeviceName = null;
|
deviceName = null;
|
||||||
mBluetoothDevice = null;
|
bluetoothDevice = null;
|
||||||
mLogSession = null;
|
logSession = null;
|
||||||
} catch (final IllegalArgumentException e) {
|
} catch (final IllegalArgumentException e) {
|
||||||
// do nothing. This should never happen but does...
|
// do nothing. This should never happen but does...
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLinkLossOccurred(final BluetoothDevice device) {
|
public void onLinkLossOccurred(@NonNull final BluetoothDevice device) {
|
||||||
// empty default implementation
|
// empty default implementation
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) {
|
public void onServicesDiscovered(@NonNull final BluetoothDevice device, final boolean optionalServicesFound) {
|
||||||
// empty default implementation
|
// empty default implementation
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceReady(final BluetoothDevice device) {
|
public void onDeviceReady(@NonNull final BluetoothDevice device) {
|
||||||
// empty default implementation
|
// empty default implementation
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBondingRequired(final BluetoothDevice device) {
|
public void onBondingRequired(@NonNull final BluetoothDevice device) {
|
||||||
// empty default implementation
|
// empty default implementation
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBonded(final BluetoothDevice device) {
|
public void onBonded(@NonNull final BluetoothDevice device) {
|
||||||
// empty default implementation
|
// empty default implementation
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBondingFailed(final BluetoothDevice device) {
|
public void onBondingFailed(@NonNull final BluetoothDevice device) {
|
||||||
// empty default implementation
|
// empty default implementation
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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);
|
DebugLogger.e(TAG, "Error occurred: " + message + ", error code: " + errorCode);
|
||||||
showToast(message + " (" + errorCode + ")");
|
showToast(message + " (" + errorCode + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceNotSupported(final BluetoothDevice device) {
|
public void onDeviceNotSupported(@NonNull final BluetoothDevice device) {
|
||||||
showToast(R.string.not_supported);
|
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.
|
* Returns <code>true</code> if the device is connected. Services may not have been discovered yet.
|
||||||
*/
|
*/
|
||||||
protected boolean isDeviceConnected() {
|
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
|
* Returns the name of the device that the phone is currently connected to or was connected last time
|
||||||
*/
|
*/
|
||||||
protected String getDeviceName() {
|
protected String getDeviceName() {
|
||||||
return mDeviceName;
|
return deviceName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -627,7 +630,7 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
|
|||||||
*/
|
*/
|
||||||
protected boolean isBroadcastForThisDevice(final Intent intent) {
|
protected boolean isBroadcastForThisDevice(final Intent intent) {
|
||||||
final BluetoothDevice bluetoothDevice = intent.getParcelableExtra(BleProfileService.EXTRA_DEVICE);
|
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>
|
* @return the logger session or <code>null</code>
|
||||||
*/
|
*/
|
||||||
protected ILogSession getLogSession() {
|
protected ILogSession getLogSession() {
|
||||||
return mLogSession;
|
return logSession;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ensureBLESupported() {
|
private void ensureBLESupported() {
|
||||||
@@ -659,8 +662,7 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isBLEEnabled() {
|
protected boolean isBLEEnabled() {
|
||||||
final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
|
final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
|
||||||
final BluetoothAdapter adapter = bluetoothManager.getAdapter();
|
|
||||||
return adapter != null && adapter.isEnabled();
|
return adapter != null && adapter.isEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,13 +17,13 @@ import no.nordicsemi.android.log.Logger;
|
|||||||
* @param <T> the callbacks class.
|
* @param <T> the callbacks class.
|
||||||
*/
|
*/
|
||||||
public abstract class LoggableBleManager<T extends BleManagerCallbacks> extends BleManager<T> {
|
public abstract class LoggableBleManager<T extends BleManagerCallbacks> extends BleManager<T> {
|
||||||
private ILogSession mLogSession;
|
private ILogSession logSession;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The manager constructor.
|
* The manager constructor.
|
||||||
* <p>
|
* <p>
|
||||||
* After constructing the manager, the callbacks object must be set with
|
* After constructing the manager, the callbacks object must be set with
|
||||||
* {@link #setGattCallbacks(BleManagerCallbacks)}.
|
* {@link #setManagerCallbacks(BleManagerCallbacks)}.
|
||||||
*
|
*
|
||||||
* @param context the context.
|
* @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.
|
* @param session nRF Logger log session to log inti, or null, if nRF Logger is not installed.
|
||||||
*/
|
*/
|
||||||
public void setLogger(@Nullable final ILogSession session) {
|
public void setLogger(@Nullable final ILogSession session) {
|
||||||
mLogSession = session;
|
logSession = session;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void log(final int priority, @NonNull final String message) {
|
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);
|
Log.println(priority, "BleManager", message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,14 +77,14 @@ public abstract class BleMulticonnectProfileService extends Service implements B
|
|||||||
public static final int STATE_CONNECTING = 2;
|
public static final int STATE_CONNECTING = 2;
|
||||||
public static final int STATE_DISCONNECTING = 3;
|
public static final int STATE_DISCONNECTING = 3;
|
||||||
|
|
||||||
private HashMap<BluetoothDevice, LoggableBleManager<BleManagerCallbacks>> mBleManagers;
|
private HashMap<BluetoothDevice, LoggableBleManager<BleManagerCallbacks>> bleManagers;
|
||||||
private List<BluetoothDevice> mManagedDevices;
|
private List<BluetoothDevice> managedDevices;
|
||||||
private Handler mHandler;
|
private Handler handler;
|
||||||
|
|
||||||
protected boolean mBound;
|
protected boolean bound;
|
||||||
private boolean mActivityIsChangingConfiguration;
|
private boolean activityIsChangingConfiguration;
|
||||||
|
|
||||||
private final BroadcastReceiver mBluetoothStateBroadcastReceiver = new BroadcastReceiver() {
|
private final BroadcastReceiver bluetoothStateBroadcastReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(final Context context, final Intent intent) {
|
public void onReceive(final Context context, final Intent intent) {
|
||||||
final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF);
|
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
|
// 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
|
// 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(...).
|
// without a delay is very likely to cause a DeadObjectException from BluetoothManager#openGattServer(...).
|
||||||
mHandler.postDelayed(() -> onBluetoothEnabled(), 600);
|
handler.postDelayed(() -> onBluetoothEnabled(), 600);
|
||||||
break;
|
break;
|
||||||
case BluetoothAdapter.STATE_TURNING_OFF:
|
case BluetoothAdapter.STATE_TURNING_OFF:
|
||||||
case BluetoothAdapter.STATE_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
|
* @return unmodifiable list of devices managed by the service
|
||||||
*/
|
*/
|
||||||
public final List<BluetoothDevice> getManagedDevices() {
|
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) {
|
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
|
// 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.
|
// 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;
|
return;
|
||||||
mManagedDevices.add(device);
|
managedDevices.add(device);
|
||||||
|
|
||||||
LoggableBleManager<BleManagerCallbacks> manager = mBleManagers.get(device);
|
LoggableBleManager<BleManagerCallbacks> manager = bleManagers.get(device);
|
||||||
if (manager != null) {
|
if (manager == null) {
|
||||||
if (session != null)
|
bleManagers.put(device, manager = initializeManager());
|
||||||
manager.setLogger(session);
|
manager.setManagerCallbacks(BleMulticonnectProfileService.this);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
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
|
* @param device target device to disconnect and forget
|
||||||
*/
|
*/
|
||||||
public void disconnect(final BluetoothDevice device) {
|
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()) {
|
if (manager != null && manager.isConnected()) {
|
||||||
manager.disconnect().enqueue();
|
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
|
* @return <code>true</code> if device is connected to the sensor, <code>false</code> otherwise
|
||||||
*/
|
*/
|
||||||
public final boolean isConnected(final BluetoothDevice device) {
|
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();
|
return manager != null && manager.isConnected();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,7 +186,7 @@ public abstract class BleMulticonnectProfileService extends Service implements B
|
|||||||
* initializing. False otherwise.
|
* initializing. False otherwise.
|
||||||
*/
|
*/
|
||||||
public final boolean isReady(final BluetoothDevice device) {
|
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();
|
return manager != null && manager.isReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,8 +195,9 @@ public abstract class BleMulticonnectProfileService extends Service implements B
|
|||||||
* @param device the target device
|
* @param device the target device
|
||||||
* @return the connection state, as in {@link BleManager#getConnectionState()}.
|
* @return the connection state, as in {@link BleManager#getConnectionState()}.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public final int getConnectionState(final BluetoothDevice device) {
|
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;
|
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
|
* @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.
|
* @deprecated Keep battery value in your manager instead.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public int getBatteryValue(final BluetoothDevice device) {
|
public int getBatteryValue(final BluetoothDevice device) {
|
||||||
final BleManager<BleManagerCallbacks> manager = mBleManagers.get(device);
|
final BleManager<BleManagerCallbacks> manager = bleManagers.get(device);
|
||||||
return manager.getBatteryValue();
|
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.
|
* If <code>false</code>, we will turn off battery level notifications in onUnbind(..) method below.
|
||||||
* @param changing true if the bound activity is finishing
|
* @param changing true if the bound activity is finishing
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("WeakerAccess")
|
||||||
public final void setActivityIsChangingConfiguration(final boolean changing) {
|
public final void setActivityIsChangingConfiguration(final boolean changing) {
|
||||||
mActivityIsChangingConfiguration = changing;
|
activityIsChangingConfiguration = changing;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void log(final BluetoothDevice device, final int level, final String message) {
|
public void log(@NonNull final BluetoothDevice device, final int level, final String message) {
|
||||||
final BleManager<BleManagerCallbacks> manager = mBleManagers.get(device);
|
final BleManager<BleManagerCallbacks> manager = bleManagers.get(device);
|
||||||
if (manager != null)
|
if (manager != null)
|
||||||
manager.log(level, message);
|
manager.log(level, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void log(final BluetoothDevice device, final int level, @StringRes final int messageRes, final Object... params) {
|
public void log(@NonNull final BluetoothDevice device, final int level, @StringRes final int messageRes, final Object... params) {
|
||||||
final BleManager<BleManagerCallbacks> manager = mBleManagers.get(device);
|
final BleManager<BleManagerCallbacks> manager = bleManagers.get(device);
|
||||||
if (manager != null)
|
if (manager != null)
|
||||||
manager.log(level, messageRes, params);
|
manager.log(level, messageRes, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void log(final int level, @NonNull final String message) {
|
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);
|
manager.log(level, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void log(final int level, @StringRes final int messageRes, final Object... params) {
|
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);
|
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.
|
* The handler may be used to postpone execution of some operations or to run them in UI thread.
|
||||||
*/
|
*/
|
||||||
protected Handler getHandler() {
|
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
|
@Override
|
||||||
public IBinder onBind(final Intent intent) {
|
public IBinder onBind(final Intent intent) {
|
||||||
mBound = true;
|
bound = true;
|
||||||
return getBinder();
|
return getBinder();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void onRebind(final Intent intent) {
|
public final void onRebind(final Intent intent) {
|
||||||
mBound = true;
|
bound = true;
|
||||||
|
|
||||||
if (!mActivityIsChangingConfiguration) {
|
if (!activityIsChangingConfiguration) {
|
||||||
onRebind();
|
onRebind();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -293,10 +306,10 @@ public abstract class BleMulticonnectProfileService extends Service implements B
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final boolean onUnbind(final Intent intent) {
|
public final boolean onUnbind(final Intent intent) {
|
||||||
mBound = false;
|
bound = false;
|
||||||
|
|
||||||
if (!mActivityIsChangingConfiguration) {
|
if (!activityIsChangingConfiguration) {
|
||||||
if (!mManagedDevices.isEmpty()) {
|
if (!managedDevices.isEmpty()) {
|
||||||
onUnbind();
|
onUnbind();
|
||||||
} else {
|
} else {
|
||||||
// The last activity has disconnected from the service and there are no devices to manage. The service may be stopped.
|
// 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() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
|
|
||||||
mHandler = new Handler();
|
handler = new Handler();
|
||||||
|
|
||||||
// Initialize the map of BLE managers
|
// Initialize the map of BLE managers
|
||||||
mBleManagers = new HashMap<>();
|
bleManagers = new HashMap<>();
|
||||||
mManagedDevices = new ArrayList<>();
|
managedDevices = new ArrayList<>();
|
||||||
|
|
||||||
// Register broadcast receivers
|
// Register broadcast receivers
|
||||||
registerReceiver(mBluetoothStateBroadcastReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
|
registerReceiver(bluetoothStateBroadcastReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
|
||||||
|
|
||||||
// Service has now been created
|
// Service has now been created
|
||||||
onServiceCreated();
|
onServiceCreated();
|
||||||
@@ -381,7 +394,7 @@ public abstract class BleMulticonnectProfileService extends Service implements B
|
|||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
onServiceStopped();
|
onServiceStopped();
|
||||||
mHandler = null;
|
handler = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -389,18 +402,18 @@ public abstract class BleMulticonnectProfileService extends Service implements B
|
|||||||
*/
|
*/
|
||||||
protected void onServiceStopped() {
|
protected void onServiceStopped() {
|
||||||
// Unregister broadcast receivers
|
// Unregister broadcast receivers
|
||||||
unregisterReceiver(mBluetoothStateBroadcastReceiver);
|
unregisterReceiver(bluetoothStateBroadcastReceiver);
|
||||||
|
|
||||||
// The managers map may not be empty if the service was killed by the system
|
// 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.
|
// Service is being destroyed, no need to disconnect manually.
|
||||||
manager.close();
|
manager.close();
|
||||||
manager.log(Log.INFO, "Service destroyed");
|
manager.log(Log.INFO, "Service destroyed");
|
||||||
}
|
}
|
||||||
mBleManagers.clear();
|
bleManagers.clear();
|
||||||
mManagedDevices.clear();
|
managedDevices.clear();
|
||||||
mBleManagers = null;
|
bleManagers = null;
|
||||||
mManagedDevices = 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.
|
* devices that were connected before the Bluetooth was turned off.
|
||||||
*/
|
*/
|
||||||
protected void onBluetoothEnabled() {
|
protected void onBluetoothEnabled() {
|
||||||
for (final BluetoothDevice device : mManagedDevices) {
|
for (final BluetoothDevice device : managedDevices) {
|
||||||
final BleManager<BleManagerCallbacks> manager = mBleManagers.get(device);
|
final BleManager<BleManagerCallbacks> manager = bleManagers.get(device);
|
||||||
if (!manager.isConnected())
|
if (manager != null && !manager.isConnected())
|
||||||
manager.connect(device).enqueue();
|
manager.connect(device).enqueue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceConnecting(final BluetoothDevice device) {
|
public void onDeviceConnecting(@NonNull final BluetoothDevice device) {
|
||||||
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
|
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
|
||||||
broadcast.putExtra(EXTRA_DEVICE, device);
|
broadcast.putExtra(EXTRA_DEVICE, device);
|
||||||
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_CONNECTING);
|
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_CONNECTING);
|
||||||
@@ -434,7 +447,7 @@ public abstract class BleMulticonnectProfileService extends Service implements B
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceConnected(final BluetoothDevice device) {
|
public void onDeviceConnected(@NonNull final BluetoothDevice device) {
|
||||||
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
|
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
|
||||||
broadcast.putExtra(EXTRA_DEVICE, device);
|
broadcast.putExtra(EXTRA_DEVICE, device);
|
||||||
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_CONNECTED);
|
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_CONNECTED);
|
||||||
@@ -442,7 +455,7 @@ public abstract class BleMulticonnectProfileService extends Service implements B
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceDisconnecting(final BluetoothDevice device) {
|
public void onDeviceDisconnecting(@NonNull final BluetoothDevice device) {
|
||||||
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
|
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
|
||||||
broadcast.putExtra(EXTRA_DEVICE, device);
|
broadcast.putExtra(EXTRA_DEVICE, device);
|
||||||
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_DISCONNECTING);
|
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_DISCONNECTING);
|
||||||
@@ -450,15 +463,15 @@ public abstract class BleMulticonnectProfileService extends Service implements B
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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
|
// 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
|
// 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.
|
// 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
|
// 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.
|
// 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
|
// Do not use the device argument here unless you change calling onDeviceDisconnected from the binder above
|
||||||
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
|
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);
|
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||||
|
|
||||||
// When user disconnected the last device while the activity was not bound the service can be stopped
|
// 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();
|
stopSelf();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLinkLossOccurred(final BluetoothDevice device) {
|
public void onLinkLossOccurred(@NonNull final BluetoothDevice device) {
|
||||||
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
|
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
|
||||||
broadcast.putExtra(EXTRA_DEVICE, device);
|
broadcast.putExtra(EXTRA_DEVICE, device);
|
||||||
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_LINK_LOSS);
|
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_LINK_LOSS);
|
||||||
@@ -481,7 +494,7 @@ public abstract class BleMulticonnectProfileService extends Service implements B
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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);
|
final Intent broadcast = new Intent(BROADCAST_SERVICES_DISCOVERED);
|
||||||
broadcast.putExtra(EXTRA_DEVICE, device);
|
broadcast.putExtra(EXTRA_DEVICE, device);
|
||||||
broadcast.putExtra(EXTRA_SERVICE_PRIMARY, true);
|
broadcast.putExtra(EXTRA_SERVICE_PRIMARY, true);
|
||||||
@@ -490,17 +503,17 @@ public abstract class BleMulticonnectProfileService extends Service implements B
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceReady(final BluetoothDevice device) {
|
public void onDeviceReady(@NonNull final BluetoothDevice device) {
|
||||||
final Intent broadcast = new Intent(BROADCAST_DEVICE_READY);
|
final Intent broadcast = new Intent(BROADCAST_DEVICE_READY);
|
||||||
broadcast.putExtra(EXTRA_DEVICE, device);
|
broadcast.putExtra(EXTRA_DEVICE, device);
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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
|
// We don't like this device, remove it from both collections
|
||||||
mManagedDevices.remove(device);
|
managedDevices.remove(device);
|
||||||
mBleManagers.remove(device);
|
bleManagers.remove(device);
|
||||||
|
|
||||||
final Intent broadcast = new Intent(BROADCAST_SERVICES_DISCOVERED);
|
final Intent broadcast = new Intent(BROADCAST_SERVICES_DISCOVERED);
|
||||||
broadcast.putExtra(EXTRA_DEVICE, device);
|
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
|
// no need for disconnecting, it will be disconnected by the manager automatically
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
@Override
|
@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);
|
final Intent broadcast = new Intent(BROADCAST_BATTERY_LEVEL);
|
||||||
broadcast.putExtra(EXTRA_DEVICE, device);
|
broadcast.putExtra(EXTRA_DEVICE, device);
|
||||||
broadcast.putExtra(EXTRA_BATTERY_LEVEL, value);
|
broadcast.putExtra(EXTRA_BATTERY_LEVEL, value);
|
||||||
@@ -520,7 +534,7 @@ public abstract class BleMulticonnectProfileService extends Service implements B
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBondingRequired(final BluetoothDevice device) {
|
public void onBondingRequired(@NonNull final BluetoothDevice device) {
|
||||||
showToast(no.nordicsemi.android.nrftoolbox.common.R.string.bonding);
|
showToast(no.nordicsemi.android.nrftoolbox.common.R.string.bonding);
|
||||||
|
|
||||||
final Intent broadcast = new Intent(BROADCAST_BOND_STATE);
|
final Intent broadcast = new Intent(BROADCAST_BOND_STATE);
|
||||||
@@ -530,7 +544,7 @@ public abstract class BleMulticonnectProfileService extends Service implements B
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBonded(final BluetoothDevice device) {
|
public void onBonded(@NonNull final BluetoothDevice device) {
|
||||||
showToast(no.nordicsemi.android.nrftoolbox.common.R.string.bonded);
|
showToast(no.nordicsemi.android.nrftoolbox.common.R.string.bonded);
|
||||||
|
|
||||||
final Intent broadcast = new Intent(BROADCAST_BOND_STATE);
|
final Intent broadcast = new Intent(BROADCAST_BOND_STATE);
|
||||||
@@ -540,7 +554,7 @@ public abstract class BleMulticonnectProfileService extends Service implements B
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBondingFailed(final BluetoothDevice device) {
|
public void onBondingFailed(@NonNull final BluetoothDevice device) {
|
||||||
showToast(no.nordicsemi.android.nrftoolbox.common.R.string.bonding_failed);
|
showToast(no.nordicsemi.android.nrftoolbox.common.R.string.bonding_failed);
|
||||||
|
|
||||||
final Intent broadcast = new Intent(BROADCAST_BOND_STATE);
|
final Intent broadcast = new Intent(BROADCAST_BOND_STATE);
|
||||||
@@ -550,7 +564,7 @@ public abstract class BleMulticonnectProfileService extends Service implements B
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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);
|
final Intent broadcast = new Intent(BROADCAST_ERROR);
|
||||||
broadcast.putExtra(EXTRA_DEVICE, device);
|
broadcast.putExtra(EXTRA_DEVICE, device);
|
||||||
broadcast.putExtra(EXTRA_ERROR_MESSAGE, message);
|
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
|
* an resource id of the message to be shown
|
||||||
*/
|
*/
|
||||||
protected void showToast(final int messageResId) {
|
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
|
* a message to be shown
|
||||||
*/
|
*/
|
||||||
protected void showToast(final String message) {
|
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
|
* @return the BleManager or null
|
||||||
*/
|
*/
|
||||||
protected BleManager<? extends BleManagerCallbacks> getBleManager(final BluetoothDevice device) {
|
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
|
* @return list of managed devices
|
||||||
*/
|
*/
|
||||||
protected List<BluetoothDevice> getManagedDevices() {
|
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() {
|
protected List<BluetoothDevice> getConnectedDevices() {
|
||||||
final List<BluetoothDevice> list = new ArrayList<>();
|
final List<BluetoothDevice> list = new ArrayList<>();
|
||||||
for (BluetoothDevice device : mManagedDevices) {
|
for (BluetoothDevice device : managedDevices) {
|
||||||
if (mBleManagers.get(device).isConnected())
|
final BleManager<BleManagerCallbacks> manager = bleManagers.get(device);
|
||||||
|
if (manager != null && manager.isConnected())
|
||||||
list.add(device);
|
list.add(device);
|
||||||
}
|
}
|
||||||
return Collections.unmodifiableList(list);
|
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
|
* @return <code>true</code> if device is connected to the sensor, <code>false</code> otherwise
|
||||||
*/
|
*/
|
||||||
protected boolean isConnected(final BluetoothDevice device) {
|
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();
|
return manager != null && manager.isConnected();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ package no.nordicsemi.android.nrftoolbox.profile.multiconnect;
|
|||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.bluetooth.BluetoothManager;
|
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -35,9 +34,6 @@ import android.content.pm.PackageManager;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
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.util.Log;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
@@ -49,6 +45,10 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
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.ble.BleManagerCallbacks;
|
||||||
import no.nordicsemi.android.log.ILogSession;
|
import no.nordicsemi.android.log.ILogSession;
|
||||||
import no.nordicsemi.android.log.LocalLogSession;
|
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.
|
* listens for updates from them. When entering back to the activity, activity will to bind to the service and refresh UI.
|
||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public abstract class BleMulticonnectProfileServiceReadyActivity<E extends BleMulticonnectProfileService.LocalBinder> extends AppCompatActivity implements
|
public abstract class BleMulticonnectProfileServiceReadyActivity<E extends BleMulticonnectProfileService.LocalBinder> extends AppCompatActivity implements
|
||||||
ScannerFragment.OnDeviceSelectedListener, BleManagerCallbacks {
|
ScannerFragment.OnDeviceSelectedListener, BleManagerCallbacks {
|
||||||
private static final String TAG = "BleMulticonnectProfileServiceReadyActivity";
|
private static final String TAG = "BleMulticonnectProfileServiceReadyActivity";
|
||||||
|
|
||||||
protected static final int REQUEST_ENABLE_BT = 2;
|
protected static final int REQUEST_ENABLE_BT = 2;
|
||||||
|
|
||||||
private E mService;
|
private E service;
|
||||||
private List<BluetoothDevice> mManagedDevices;
|
private List<BluetoothDevice> managedDevices;
|
||||||
|
|
||||||
private final BroadcastReceiver mCommonBroadcastReceiver = new BroadcastReceiver() {
|
private final BroadcastReceiver commonBroadcastReceiver = new BroadcastReceiver() {
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(final Context context, final Intent intent) {
|
public void onReceive(final Context context, final Intent intent) {
|
||||||
final BluetoothDevice bluetoothDevice = intent.getParcelableExtra(BleMulticonnectProfileService.EXTRA_DEVICE);
|
final BluetoothDevice bluetoothDevice = intent.getParcelableExtra(BleMulticonnectProfileService.EXTRA_DEVICE);
|
||||||
|
if (bluetoothDevice == null)
|
||||||
|
return;
|
||||||
|
|
||||||
final String action = intent.getAction();
|
final String action = intent.getAction();
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case BleMulticonnectProfileService.BROADCAST_CONNECTION_STATE: {
|
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")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public void onServiceConnected(final ComponentName name, final IBinder service) {
|
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");
|
bleService.log(Log.DEBUG, "Activity bound to the service");
|
||||||
mManagedDevices.addAll(bleService.getManagedDevices());
|
managedDevices.addAll(bleService.getManagedDevices());
|
||||||
onServiceBound(bleService);
|
onServiceBound(bleService);
|
||||||
|
|
||||||
// and notify user if device is connected
|
// and notify user if device is connected
|
||||||
for (final BluetoothDevice device : mManagedDevices) {
|
for (final BluetoothDevice device : managedDevices) {
|
||||||
if (bleService.isConnected(device))
|
if (bleService.isConnected(device))
|
||||||
onDeviceConnected(device);
|
onDeviceConnected(device);
|
||||||
}
|
}
|
||||||
@@ -177,7 +182,7 @@ public abstract class BleMulticonnectProfileServiceReadyActivity<E extends BleMu
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onServiceDisconnected(final ComponentName name) {
|
public void onServiceDisconnected(final ComponentName name) {
|
||||||
mService = null;
|
service = null;
|
||||||
onServiceUnbound();
|
onServiceUnbound();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -185,7 +190,7 @@ public abstract class BleMulticonnectProfileServiceReadyActivity<E extends BleMu
|
|||||||
@Override
|
@Override
|
||||||
protected final void onCreate(final Bundle savedInstanceState) {
|
protected final void onCreate(final Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
mManagedDevices = new ArrayList<>();
|
managedDevices = new ArrayList<>();
|
||||||
|
|
||||||
ensureBLESupported();
|
ensureBLESupported();
|
||||||
if (!isBLEEnabled()) {
|
if (!isBLEEnabled()) {
|
||||||
@@ -205,7 +210,7 @@ public abstract class BleMulticonnectProfileServiceReadyActivity<E extends BleMu
|
|||||||
// View is ready to be used
|
// View is ready to be used
|
||||||
onViewCreated(savedInstanceState);
|
onViewCreated(savedInstanceState);
|
||||||
|
|
||||||
LocalBroadcastManager.getInstance(this).registerReceiver(mCommonBroadcastReceiver, makeIntentFilter());
|
LocalBroadcastManager.getInstance(this).registerReceiver(commonBroadcastReceiver, makeIntentFilter());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -214,29 +219,29 @@ public abstract class BleMulticonnectProfileServiceReadyActivity<E extends BleMu
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* In comparison to BleProfileServiceReadyActivity this activity always starts the service when started.
|
* 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.
|
* 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());
|
final Intent service = new Intent(this, getServiceClass());
|
||||||
startService(service);
|
startService(service);
|
||||||
bindService(service, mServiceConnection, 0);
|
bindService(service, serviceConnection, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStop() {
|
protected void onStop() {
|
||||||
super.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.
|
// 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.
|
// 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
|
// 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)
|
// and the service will not be available later (the activity doesn't keep log sessions)
|
||||||
mService.log(Log.DEBUG, "Activity unbound from the service");
|
service.log(Log.DEBUG, "Activity unbound from the service");
|
||||||
}
|
}
|
||||||
|
|
||||||
unbindService(mServiceConnection);
|
unbindService(serviceConnection);
|
||||||
mService = null;
|
service = null;
|
||||||
|
|
||||||
onServiceUnbound();
|
onServiceUnbound();
|
||||||
}
|
}
|
||||||
@@ -245,7 +250,7 @@ public abstract class BleMulticonnectProfileServiceReadyActivity<E extends BleMu
|
|||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
|
|
||||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(mCommonBroadcastReceiver);
|
LocalBroadcastManager.getInstance(this).unregisterReceiver(commonBroadcastReceiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IntentFilter makeIntentFilter() {
|
private static IntentFilter makeIntentFilter() {
|
||||||
@@ -284,7 +289,7 @@ public abstract class BleMulticonnectProfileServiceReadyActivity<E extends BleMu
|
|||||||
* @return the service binder or <code>null</code>
|
* @return the service binder or <code>null</code>
|
||||||
*/
|
*/
|
||||||
protected E getService() {
|
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)}.
|
* @param savedInstanceState contains the data it most recently supplied in {@link #onSaveInstanceState(Bundle)}.
|
||||||
* Note: <b>Otherwise it is null</b>.
|
* Note: <b>Otherwise it is null</b>.
|
||||||
*/
|
*/
|
||||||
protected void onViewCreated(final Bundle savedInstanceState) {
|
protected void onViewCreated(@SuppressWarnings("unused") final Bundle savedInstanceState) {
|
||||||
// empty default implementation
|
// empty default implementation
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,7 +338,7 @@ public abstract class BleMulticonnectProfileServiceReadyActivity<E extends BleMu
|
|||||||
* @param itemId the menu item id
|
* @param itemId the menu item id
|
||||||
* @return <code>true</code> if action has been handled
|
* @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
|
// Overwrite when using menu other than R.menu.help
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -385,7 +390,7 @@ public abstract class BleMulticonnectProfileServiceReadyActivity<E extends BleMu
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceSelected(final BluetoothDevice device, final String name) {
|
public void onDeviceSelected(@NonNull final BluetoothDevice device, final String name) {
|
||||||
final int titleId = getLoggerProfileTitle();
|
final int titleId = getLoggerProfileTitle();
|
||||||
ILogSession logSession = null;
|
ILogSession logSession = null;
|
||||||
if (titleId > 0) {
|
if (titleId > 0) {
|
||||||
@@ -396,7 +401,7 @@ public abstract class BleMulticonnectProfileServiceReadyActivity<E extends BleMu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mService.connect(device, logSession);
|
service.connect(device, logSession);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -405,64 +410,66 @@ public abstract class BleMulticonnectProfileServiceReadyActivity<E extends BleMu
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceConnecting(final BluetoothDevice device) {
|
public void onDeviceConnecting(@NonNull final BluetoothDevice device) {
|
||||||
// empty default implementation
|
// empty default implementation
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceDisconnecting(final BluetoothDevice device) {
|
public void onDeviceDisconnecting(@NonNull final BluetoothDevice device) {
|
||||||
// empty default implementation
|
// empty default implementation
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLinkLossOccurred(final BluetoothDevice device) {
|
public void onLinkLossOccurred(@NonNull final BluetoothDevice device) {
|
||||||
// empty default implementation
|
// empty default implementation
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) {
|
public void onServicesDiscovered(@NonNull final BluetoothDevice device, final boolean optionalServicesFound) {
|
||||||
// empty default implementation
|
// empty default implementation
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceReady(final BluetoothDevice device) {
|
public void onDeviceReady(@NonNull final BluetoothDevice device) {
|
||||||
// empty default implementation
|
// empty default implementation
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBondingRequired(final BluetoothDevice device) {
|
public void onBondingRequired(@NonNull final BluetoothDevice device) {
|
||||||
// empty default implementation
|
// empty default implementation
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBonded(final BluetoothDevice device) {
|
public void onBonded(@NonNull final BluetoothDevice device) {
|
||||||
// empty default implementation
|
// empty default implementation
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBondingFailed(final BluetoothDevice device) {
|
public void onBondingFailed(@NonNull final BluetoothDevice device) {
|
||||||
// empty default implementation
|
// empty default implementation
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceNotSupported(final BluetoothDevice device) {
|
public void onDeviceNotSupported(@NonNull final BluetoothDevice device) {
|
||||||
showToast(R.string.not_supported);
|
showToast(R.string.not_supported);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
@Override
|
@Override
|
||||||
public final boolean shouldEnableBatteryLevelNotifications(final BluetoothDevice device) {
|
public final boolean shouldEnableBatteryLevelNotifications(@NonNull final BluetoothDevice device) {
|
||||||
// This method will never be called.
|
// This method will never be called.
|
||||||
// Please see BleMulticonnectProfileService#shouldEnableBatteryLevelNotifications(BluetoothDevice) instead.
|
// Please see BleMulticonnectProfileService#shouldEnableBatteryLevelNotifications(BluetoothDevice) instead.
|
||||||
throw new UnsupportedOperationException("This method should not be called");
|
throw new UnsupportedOperationException("This method should not be called");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
@Override
|
@Override
|
||||||
public void onBatteryValueReceived(final BluetoothDevice device, final int value) {
|
public void onBatteryValueReceived(@NonNull final BluetoothDevice device, final int value) {
|
||||||
// empty default implementation
|
// empty default implementation
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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);
|
DebugLogger.e(TAG, "Error occurred: " + message + ", error code: " + errorCode);
|
||||||
showToast(message + " (" + errorCode + ")");
|
showToast(message + " (" + errorCode + ")");
|
||||||
}
|
}
|
||||||
@@ -506,7 +513,7 @@ public abstract class BleMulticonnectProfileServiceReadyActivity<E extends BleMu
|
|||||||
* @return unmodifiable list of managed devices
|
* @return unmodifiable list of managed devices
|
||||||
*/
|
*/
|
||||||
protected List<BluetoothDevice> getManagedDevices() {
|
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
|
* @param device the device to check if it's connected
|
||||||
*/
|
*/
|
||||||
protected boolean isDeviceConnected(final BluetoothDevice device) {
|
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() {
|
protected boolean isBLEEnabled() {
|
||||||
final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
|
final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
|
||||||
final BluetoothAdapter adapter = bluetoothManager.getAdapter();
|
|
||||||
return adapter != null && adapter.isEnabled();
|
return adapter != null && adapter.isEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,8 @@
|
|||||||
package no.nordicsemi.android.nrftoolbox.profile.multiconnect;
|
package no.nordicsemi.android.nrftoolbox.profile.multiconnect;
|
||||||
|
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.StringRes;
|
import androidx.annotation.StringRes;
|
||||||
|
|
||||||
public interface IDeviceLogger {
|
public interface IDeviceLogger {
|
||||||
@@ -32,7 +34,7 @@ public interface IDeviceLogger {
|
|||||||
* @param level the log level
|
* @param level the log level
|
||||||
* @param message the message to be logged
|
* @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.
|
* 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 messageRes string resource id
|
||||||
* @param params additional (optional) parameters used to fill the message
|
* @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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,12 +38,12 @@ import java.util.List;
|
|||||||
import no.nordicsemi.android.nrftoolbox.R;
|
import no.nordicsemi.android.nrftoolbox.R;
|
||||||
|
|
||||||
public class DeviceAdapter extends RecyclerView.Adapter<DeviceAdapter.ViewHolder> {
|
public class DeviceAdapter extends RecyclerView.Adapter<DeviceAdapter.ViewHolder> {
|
||||||
private final ProximityService.ProximityBinder mService;
|
private final ProximityService.ProximityBinder service;
|
||||||
private final List<BluetoothDevice> mDevices;
|
private final List<BluetoothDevice> devices;
|
||||||
|
|
||||||
DeviceAdapter(final ProximityService.ProximityBinder binder) {
|
DeviceAdapter(final ProximityService.ProximityBinder binder) {
|
||||||
mService = binder;
|
service = binder;
|
||||||
mDevices = mService.getManagedDevices();
|
devices = service.getManagedDevices();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@@ -55,18 +55,18 @@ public class DeviceAdapter extends RecyclerView.Adapter<DeviceAdapter.ViewHolder
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(@NonNull final ViewHolder holder, final int position) {
|
public void onBindViewHolder(@NonNull final ViewHolder holder, final int position) {
|
||||||
holder.bind(mDevices.get(position));
|
holder.bind(devices.get(position));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getItemCount() {
|
public int getItemCount() {
|
||||||
return mDevices.size();
|
return devices.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onDeviceAdded(final BluetoothDevice device) {
|
public void onDeviceAdded(final BluetoothDevice device) {
|
||||||
final int position = mDevices.indexOf(device);
|
final int position = devices.indexOf(device);
|
||||||
if (position == -1) {
|
if (position == -1) {
|
||||||
notifyItemInserted(mDevices.size() - 1);
|
notifyItemInserted(devices.size() - 1);
|
||||||
} else {
|
} else {
|
||||||
// This may happen when Bluetooth adapter was switched off and on again
|
// This may happen when Bluetooth adapter was switched off and on again
|
||||||
// while there were devices on the list.
|
// 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) {
|
public void onDeviceStateChanged(final BluetoothDevice device) {
|
||||||
final int position = mDevices.indexOf(device);
|
final int position = devices.indexOf(device);
|
||||||
if (position >= 0)
|
if (position >= 0)
|
||||||
notifyItemChanged(position);
|
notifyItemChanged(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onBatteryValueReceived(final BluetoothDevice device) {
|
public void onBatteryValueReceived(final BluetoothDevice device) {
|
||||||
final int position = mDevices.indexOf(device);
|
final int position = devices.indexOf(device);
|
||||||
if (position >= 0)
|
if (position >= 0)
|
||||||
notifyItemChanged(position);
|
notifyItemChanged(position);
|
||||||
}
|
}
|
||||||
@@ -109,22 +109,22 @@ public class DeviceAdapter extends RecyclerView.Adapter<DeviceAdapter.ViewHolder
|
|||||||
// Configure FIND / SILENT button
|
// Configure FIND / SILENT button
|
||||||
actionButton.setOnClickListener(v -> {
|
actionButton.setOnClickListener(v -> {
|
||||||
final int position = getAdapterPosition();
|
final int position = getAdapterPosition();
|
||||||
final BluetoothDevice device = mDevices.get(position);
|
final BluetoothDevice device = devices.get(position);
|
||||||
mService.toggleImmediateAlert(device);
|
service.toggleImmediateAlert(device);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Configure Disconnect button
|
// Configure Disconnect button
|
||||||
itemView.findViewById(R.id.action_disconnect).setOnClickListener(v -> {
|
itemView.findViewById(R.id.action_disconnect).setOnClickListener(v -> {
|
||||||
final int position = getAdapterPosition();
|
final int position = getAdapterPosition();
|
||||||
final BluetoothDevice device = mDevices.get(position);
|
final BluetoothDevice device = devices.get(position);
|
||||||
mService.disconnect(device);
|
service.disconnect(device);
|
||||||
// The device might have not been connected, so there will be no callback
|
// The device might have not been connected, so there will be no callback
|
||||||
onDeviceRemoved(device);
|
onDeviceRemoved(device);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void bind(final BluetoothDevice device) {
|
private void bind(final BluetoothDevice device) {
|
||||||
final boolean ready = mService.isReady(device);
|
final boolean ready = service.isReady(device);
|
||||||
|
|
||||||
String name = device.getName();
|
String name = device.getName();
|
||||||
if (TextUtils.isEmpty(name))
|
if (TextUtils.isEmpty(name))
|
||||||
@@ -132,12 +132,12 @@ public class DeviceAdapter extends RecyclerView.Adapter<DeviceAdapter.ViewHolder
|
|||||||
nameView.setText(name);
|
nameView.setText(name);
|
||||||
addressView.setText(device.getAddress());
|
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.setImageResource(on ? R.drawable.ic_stat_notify_proximity_silent : R.drawable.ic_stat_notify_proximity_find);
|
||||||
actionButton.setVisibility(ready ? View.VISIBLE : View.GONE);
|
actionButton.setVisibility(ready ? View.VISIBLE : View.GONE);
|
||||||
progress.setVisibility(ready ? View.GONE : View.VISIBLE);
|
progress.setVisibility(ready ? View.GONE : View.VISIBLE);
|
||||||
|
|
||||||
final Integer batteryValue = mService.getBatteryLevel(device);
|
final Integer batteryValue = service.getBatteryLevel(device);
|
||||||
if (batteryValue != null) {
|
if (batteryValue != null) {
|
||||||
batteryView.getCompoundDrawables()[0 /*left*/].setLevel(batteryValue);
|
batteryView.getCompoundDrawables()[0 /*left*/].setLevel(batteryValue);
|
||||||
batteryView.setVisibility(View.VISIBLE);
|
batteryView.setVisibility(View.VISIBLE);
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import no.nordicsemi.android.nrftoolbox.R;
|
|||||||
public class LinkLossFragment extends DialogFragment {
|
public class LinkLossFragment extends DialogFragment {
|
||||||
private static final String ARG_NAME = "name";
|
private static final String ARG_NAME = "name";
|
||||||
|
|
||||||
private String mName;
|
private String name;
|
||||||
|
|
||||||
public static LinkLossFragment getInstance(String name) {
|
public static LinkLossFragment getInstance(String name) {
|
||||||
final LinkLossFragment fragment = new LinkLossFragment();
|
final LinkLossFragment fragment = new LinkLossFragment();
|
||||||
@@ -48,7 +48,7 @@ public class LinkLossFragment extends DialogFragment {
|
|||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
mName = getArguments().getString(ARG_NAME);
|
name = getArguments().getString(ARG_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@@ -56,7 +56,7 @@ public class LinkLossFragment extends DialogFragment {
|
|||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
return new AlertDialog.Builder(requireContext())
|
return new AlertDialog.Builder(requireContext())
|
||||||
.setTitle(getString(R.string.app_name))
|
.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)
|
.setPositiveButton(R.string.ok, null)
|
||||||
.create();
|
.create();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
@@ -40,8 +42,8 @@ import no.nordicsemi.android.nrftoolbox.profile.multiconnect.BleMulticonnectProf
|
|||||||
import no.nordicsemi.android.nrftoolbox.widget.DividerItemDecoration;
|
import no.nordicsemi.android.nrftoolbox.widget.DividerItemDecoration;
|
||||||
|
|
||||||
public class ProximityActivity extends BleMulticonnectProfileServiceReadyActivity<ProximityService.ProximityBinder> {
|
public class ProximityActivity extends BleMulticonnectProfileServiceReadyActivity<ProximityService.ProximityBinder> {
|
||||||
private RecyclerView mDevicesView;
|
private RecyclerView devicesView;
|
||||||
private DeviceAdapter mAdapter;
|
private DeviceAdapter adapter;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreateView(final Bundle savedInstanceState) {
|
protected void onCreateView(final Bundle savedInstanceState) {
|
||||||
@@ -51,17 +53,17 @@ public class ProximityActivity extends BleMulticonnectProfileServiceReadyActivit
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onInitialize(final Bundle savedInstanceState) {
|
protected void onInitialize(final Bundle savedInstanceState) {
|
||||||
LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, makeIntentFilter());
|
LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, makeIntentFilter());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver);
|
LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setGUI() {
|
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.setLayoutManager(new LinearLayoutManager(this));
|
||||||
recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));
|
recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));
|
||||||
}
|
}
|
||||||
@@ -73,12 +75,12 @@ public class ProximityActivity extends BleMulticonnectProfileServiceReadyActivit
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onServiceBound(final ProximityService.ProximityBinder binder) {
|
protected void onServiceBound(final ProximityService.ProximityBinder binder) {
|
||||||
mDevicesView.setAdapter(mAdapter = new DeviceAdapter(binder));
|
devicesView.setAdapter(adapter = new DeviceAdapter(binder));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onServiceUnbound() {
|
protected void onServiceUnbound() {
|
||||||
mDevicesView.setAdapter(mAdapter = null);
|
devicesView.setAdapter(adapter = null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -97,46 +99,46 @@ public class ProximityActivity extends BleMulticonnectProfileServiceReadyActivit
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceConnecting(final BluetoothDevice device) {
|
public void onDeviceConnecting(@NonNull final BluetoothDevice device) {
|
||||||
if (mAdapter != null)
|
if (adapter != null)
|
||||||
mAdapter.onDeviceAdded(device);
|
adapter.onDeviceAdded(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceConnected(final BluetoothDevice device) {
|
public void onDeviceConnected(final BluetoothDevice device) {
|
||||||
if (mAdapter != null)
|
if (adapter != null)
|
||||||
mAdapter.onDeviceStateChanged(device);
|
adapter.onDeviceStateChanged(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceReady(final BluetoothDevice device) {
|
public void onDeviceReady(@NonNull final BluetoothDevice device) {
|
||||||
if (mAdapter != null)
|
if (adapter != null)
|
||||||
mAdapter.onDeviceStateChanged(device);
|
adapter.onDeviceStateChanged(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceDisconnecting(final BluetoothDevice device) {
|
public void onDeviceDisconnecting(@NonNull final BluetoothDevice device) {
|
||||||
if (mAdapter != null)
|
if (adapter != null)
|
||||||
mAdapter.onDeviceStateChanged(device);
|
adapter.onDeviceStateChanged(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceDisconnected(final BluetoothDevice device) {
|
public void onDeviceDisconnected(final BluetoothDevice device) {
|
||||||
if (mAdapter != null)
|
if (adapter != null)
|
||||||
mAdapter.onDeviceRemoved(device);
|
adapter.onDeviceRemoved(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceNotSupported(final BluetoothDevice device) {
|
public void onDeviceNotSupported(@NonNull final BluetoothDevice device) {
|
||||||
super.onDeviceNotSupported(device);
|
super.onDeviceNotSupported(device);
|
||||||
if (mAdapter != null)
|
if (adapter != null)
|
||||||
mAdapter.onDeviceRemoved(device);
|
adapter.onDeviceRemoved(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLinkLossOccurred(final BluetoothDevice device) {
|
public void onLinkLossOccurred(@NonNull final BluetoothDevice device) {
|
||||||
if (mAdapter != null)
|
if (adapter != null)
|
||||||
mAdapter.onDeviceStateChanged(device);
|
adapter.onDeviceStateChanged(device);
|
||||||
|
|
||||||
// The link loss may also be called when Bluetooth adapter was disabled
|
// The link loss may also be called when Bluetooth adapter was disabled
|
||||||
if (BluetoothAdapter.getDefaultAdapter().isEnabled())
|
if (BluetoothAdapter.getDefaultAdapter().isEnabled())
|
||||||
@@ -145,14 +147,14 @@ public class ProximityActivity extends BleMulticonnectProfileServiceReadyActivit
|
|||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private void onBatteryLevelChanged(final BluetoothDevice device, final int batteryLevel) {
|
private void onBatteryLevelChanged(final BluetoothDevice device, final int batteryLevel) {
|
||||||
if (mAdapter != null)
|
if (adapter != null)
|
||||||
mAdapter.onBatteryValueReceived(device); // Value will be obtained from the service
|
adapter.onBatteryValueReceived(device); // Value will be obtained from the service
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private void onRemoteAlarmSwitched(final BluetoothDevice device, final boolean on) {
|
private void onRemoteAlarmSwitched(final BluetoothDevice device, final boolean on) {
|
||||||
if (mAdapter != null)
|
if (adapter != null)
|
||||||
mAdapter.onDeviceStateChanged(device); // Value will be obtained from the service
|
adapter.onDeviceStateChanged(device); // Value will be obtained from the service
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showLinkLossDialog(final String name) {
|
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
|
@Override
|
||||||
public void onReceive(final Context context, final Intent intent) {
|
public void onReceive(final Context context, final Intent intent) {
|
||||||
final String action = intent.getAction();
|
final String action = intent.getAction();
|
||||||
|
|||||||
@@ -21,8 +21,10 @@
|
|||||||
*/
|
*/
|
||||||
package no.nordicsemi.android.nrftoolbox.proximity;
|
package no.nordicsemi.android.nrftoolbox.proximity;
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.bluetooth.BluetoothGatt;
|
import android.bluetooth.BluetoothGatt;
|
||||||
import android.bluetooth.BluetoothGattCharacteristic;
|
import android.bluetooth.BluetoothGattCharacteristic;
|
||||||
|
import android.bluetooth.BluetoothGattServer;
|
||||||
import android.bluetooth.BluetoothGattService;
|
import android.bluetooth.BluetoothGattService;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
@@ -31,6 +33,7 @@ import android.util.Log;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import no.nordicsemi.android.ble.callback.FailCallback;
|
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.common.data.alert.AlertLevelData;
|
||||||
import no.nordicsemi.android.ble.error.GattError;
|
import no.nordicsemi.android.ble.error.GattError;
|
||||||
import no.nordicsemi.android.log.LogContract;
|
import no.nordicsemi.android.log.LogContract;
|
||||||
@@ -42,50 +45,67 @@ class ProximityManager extends BatteryManager<ProximityManagerCallbacks> {
|
|||||||
/** Link Loss service UUID. */
|
/** Link Loss service UUID. */
|
||||||
final static UUID LINK_LOSS_SERVICE_UUID = UUID.fromString("00001803-0000-1000-8000-00805f9b34fb");
|
final static UUID LINK_LOSS_SERVICE_UUID = UUID.fromString("00001803-0000-1000-8000-00805f9b34fb");
|
||||||
/** Immediate Alert service UUID. */
|
/** 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. */
|
/** 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;
|
// Client characteristics.
|
||||||
private boolean mAlertOn;
|
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) {
|
ProximityManager(final Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean shouldAutoConnect() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
protected BatteryManagerGattCallback getGattCallback() {
|
protected BatteryManagerGattCallback getGattCallback() {
|
||||||
return mGattCallback;
|
return gattCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BluetoothGatt callbacks for connection/disconnection, service discovery,
|
* BluetoothGatt callbacks for connection/disconnection, service discovery,
|
||||||
* receiving indication, etc.
|
* receiving indication, etc.
|
||||||
*/
|
*/
|
||||||
private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() {
|
private final BatteryManagerGattCallback gattCallback = new BatteryManagerGattCallback() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initialize() {
|
protected void initialize() {
|
||||||
super.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"))
|
.done(device -> log(Log.INFO, "Link loss alert level set"))
|
||||||
.fail((device, status) -> log(Log.WARN, "Failed to set link loss level: " + status))
|
.fail((device, status) -> log(Log.WARN, "Failed to set link loss level: " + status))
|
||||||
.enqueue();
|
.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
|
@Override
|
||||||
protected boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) {
|
protected boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) {
|
||||||
final BluetoothGattService llService = gatt.getService(LINK_LOSS_SERVICE_UUID);
|
final BluetoothGattService llService = gatt.getService(LINK_LOSS_SERVICE_UUID);
|
||||||
if (llService != null) {
|
if (llService != null) {
|
||||||
mLinkLossCharacteristic = llService.getCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID);
|
linkLossCharacteristic = llService.getCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID);
|
||||||
}
|
}
|
||||||
return mLinkLossCharacteristic != null;
|
return linkLossCharacteristic != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -93,18 +113,19 @@ class ProximityManager extends BatteryManager<ProximityManagerCallbacks> {
|
|||||||
super.isOptionalServiceSupported(gatt);
|
super.isOptionalServiceSupported(gatt);
|
||||||
final BluetoothGattService iaService = gatt.getService(IMMEDIATE_ALERT_SERVICE_UUID);
|
final BluetoothGattService iaService = gatt.getService(IMMEDIATE_ALERT_SERVICE_UUID);
|
||||||
if (iaService != null) {
|
if (iaService != null) {
|
||||||
mAlertLevelCharacteristic = iaService.getCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID);
|
alertLevelCharacteristic = iaService.getCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID);
|
||||||
}
|
}
|
||||||
return mAlertLevelCharacteristic != null;
|
return alertLevelCharacteristic != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDeviceDisconnected() {
|
protected void onDeviceDisconnected() {
|
||||||
super.onDeviceDisconnected();
|
super.onDeviceDisconnected();
|
||||||
mAlertLevelCharacteristic = null;
|
alertLevelCharacteristic = null;
|
||||||
mLinkLossCharacteristic = null;
|
linkLossCharacteristic = null;
|
||||||
|
localAlertLevelCharacteristic = null;
|
||||||
// Reset the alert flag
|
// 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.
|
* Toggles the immediate alert on the target device.
|
||||||
*/
|
*/
|
||||||
public void toggleImmediateAlert() {
|
public void toggleImmediateAlert() {
|
||||||
writeImmediateAlert(!mAlertOn);
|
writeImmediateAlert(!alertOn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,14 +145,14 @@ class ProximityManager extends BatteryManager<ProximityManagerCallbacks> {
|
|||||||
if (!isConnected())
|
if (!isConnected())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
writeCharacteristic(mAlertLevelCharacteristic, on ? AlertLevelData.highAlert() : AlertLevelData.noAlert())
|
writeCharacteristic(alertLevelCharacteristic, on ? AlertLevelData.highAlert() : AlertLevelData.noAlert())
|
||||||
.before(device -> log(Log.VERBOSE,
|
.before(device -> log(Log.VERBOSE,
|
||||||
on ? "Setting alarm to HIGH..." : "Disabling alarm..."))
|
on ? "Setting alarm to HIGH..." : "Disabling alarm..."))
|
||||||
.with((device, data) -> log(LogContract.Log.Level.APPLICATION,
|
.with((device, data) -> log(LogContract.Log.Level.APPLICATION,
|
||||||
"\"" + AlertLevelParser.parse(data) + "\" sent"))
|
"\"" + AlertLevelParser.parse(data) + "\" sent"))
|
||||||
.done(device -> {
|
.done(device -> {
|
||||||
mAlertOn = on;
|
alertOn = on;
|
||||||
mCallbacks.onRemoteAlarmSwitched(device, on);
|
callbacks.onRemoteAlarmSwitched(device, on);
|
||||||
})
|
})
|
||||||
.fail((device, status) -> log(Log.WARN,
|
.fail((device, status) -> log(Log.WARN,
|
||||||
status == FailCallback.REASON_NULL_ATTRIBUTE ?
|
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.
|
* Returns true if the alert has been enabled on the proximity tag, false otherwise.
|
||||||
*/
|
*/
|
||||||
boolean isAlertEnabled() {
|
boolean isAlertEnabled() {
|
||||||
return mAlertOn;
|
return alertOn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import androidx.annotation.NonNull;
|
|||||||
import no.nordicsemi.android.nrftoolbox.battery.BatteryManagerCallbacks;
|
import no.nordicsemi.android.nrftoolbox.battery.BatteryManagerCallbacks;
|
||||||
|
|
||||||
interface ProximityManagerCallbacks extends BatteryManagerCallbacks {
|
interface ProximityManagerCallbacks extends BatteryManagerCallbacks {
|
||||||
// No additional methods
|
|
||||||
void onRemoteAlarmSwitched(@NonNull final BluetoothDevice device, final boolean on);
|
void onRemoteAlarmSwitched(@NonNull final BluetoothDevice device, final boolean on);
|
||||||
|
|
||||||
|
void onLocalAlarmSwitched(@NonNull final BluetoothDevice device, final boolean on);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,366 +21,46 @@
|
|||||||
*/
|
*/
|
||||||
package no.nordicsemi.android.nrftoolbox.proximity;
|
package no.nordicsemi.android.nrftoolbox.proximity;
|
||||||
|
|
||||||
import android.bluetooth.BluetoothDevice;
|
|
||||||
import android.bluetooth.BluetoothGatt;
|
|
||||||
import android.bluetooth.BluetoothGattCharacteristic;
|
import android.bluetooth.BluetoothGattCharacteristic;
|
||||||
import android.bluetooth.BluetoothGattDescriptor;
|
|
||||||
import android.bluetooth.BluetoothGattServer;
|
|
||||||
import android.bluetooth.BluetoothGattServerCallback;
|
|
||||||
import android.bluetooth.BluetoothGattService;
|
import android.bluetooth.BluetoothGattService;
|
||||||
import android.bluetooth.BluetoothManager;
|
|
||||||
import android.bluetooth.BluetoothProfile;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Handler;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import no.nordicsemi.android.error.GattError;
|
import androidx.annotation.NonNull;
|
||||||
import no.nordicsemi.android.log.LogContract;
|
import no.nordicsemi.android.ble.BleServerManager;
|
||||||
import no.nordicsemi.android.nrftoolbox.parser.AlertLevelParser;
|
import no.nordicsemi.android.ble.common.data.alert.AlertLevelData;
|
||||||
import no.nordicsemi.android.nrftoolbox.profile.multiconnect.IDeviceLogger;
|
|
||||||
import no.nordicsemi.android.nrftoolbox.utility.ParserUtils;
|
|
||||||
|
|
||||||
class ProximityServerManager {
|
class ProximityServerManager extends BleServerManager {
|
||||||
private final String TAG = "ProximityServerManager";
|
|
||||||
|
|
||||||
/** Immediate Alert service UUID */
|
ProximityServerManager(@NonNull final Context context) {
|
||||||
final static UUID IMMEDIATE_ALERT_SERVICE_UUID = UUID.fromString("00001802-0000-1000-8000-00805f9b34fb");
|
super(context);
|
||||||
/** 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(final ProximityServerManagerCallbacks callbacks) {
|
@Override
|
||||||
mHandler = new Handler();
|
public void log(final int priority, @NonNull final String message) {
|
||||||
mCallbacks = callbacks;
|
Log.println(priority, "BleManager", message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@NonNull
|
||||||
* Sets the logger object. Logger is used to create logs in nRF Logger application.
|
@Override
|
||||||
*
|
protected List<BluetoothGattService> initializeServer() {
|
||||||
* @param logger the logger object
|
final List<BluetoothGattService> services = new ArrayList<>();
|
||||||
*/
|
services.add(
|
||||||
public void setLogger(final IDeviceLogger logger) {
|
service(ProximityManager.IMMEDIATE_ALERT_SERVICE_UUID,
|
||||||
mLogger = logger;
|
characteristic(ProximityManager.ALERT_LEVEL_CHARACTERISTIC_UUID,
|
||||||
}
|
BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE,
|
||||||
|
BluetoothGattCharacteristic.PERMISSION_WRITE))
|
||||||
/**
|
);
|
||||||
* Opens GATT server and creates 2 services: Link Loss Service and Immediate Alert Service.
|
services.add(
|
||||||
* The callback is called when initialization is complete.
|
service(ProximityManager.LINK_LOSS_SERVICE_UUID,
|
||||||
*
|
characteristic(ProximityManager.ALERT_LEVEL_CHARACTERISTIC_UUID,
|
||||||
* @param context the context.
|
BluetoothGattCharacteristic.PROPERTY_WRITE | BluetoothGattCharacteristic.PROPERTY_READ,
|
||||||
* @param callback optional callback notifying when all services has been added.
|
BluetoothGattCharacteristic.PERMISSION_WRITE | BluetoothGattCharacteristic.PERMISSION_READ,
|
||||||
*/
|
AlertLevelData.highAlert()))
|
||||||
public void openGattServer(final Context context, final OnServerOpenCallback callback) {
|
);
|
||||||
// Is the server already open?
|
return services;
|
||||||
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->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";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -47,6 +47,7 @@ import androidx.core.app.NotificationCompat;
|
|||||||
import androidx.core.app.NotificationManagerCompat;
|
import androidx.core.app.NotificationManagerCompat;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||||
|
import no.nordicsemi.android.ble.BleServerManagerCallbacks;
|
||||||
import no.nordicsemi.android.log.LogContract;
|
import no.nordicsemi.android.log.LogContract;
|
||||||
import no.nordicsemi.android.nrftoolbox.FeaturesActivity;
|
import no.nordicsemi.android.nrftoolbox.FeaturesActivity;
|
||||||
import no.nordicsemi.android.nrftoolbox.R;
|
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.LoggableBleManager;
|
||||||
import no.nordicsemi.android.nrftoolbox.profile.multiconnect.BleMulticonnectProfileService;
|
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")
|
@SuppressWarnings("unused")
|
||||||
private static final String TAG = "ProximityService";
|
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 FIND_REQ = 2;
|
||||||
private final static int SILENT_REQ = 3;
|
private final static int SILENT_REQ = 3;
|
||||||
|
|
||||||
private final ProximityBinder mBinder = new ProximityBinder();
|
private final ProximityBinder binder = new ProximityBinder();
|
||||||
private ProximityServerManager mServerManager;
|
private ProximityServerManager serverManager;
|
||||||
private MediaPlayer mMediaPlayer;
|
private MediaPlayer mediaPlayer;
|
||||||
private int mOriginalVolume;
|
private int originalVolume;
|
||||||
/**
|
/**
|
||||||
* When a device starts an alarm on the phone it is added to this list.
|
* When a device starts an alarm on the phone it is added to this list.
|
||||||
* Alarm is disabled when this list is empty.
|
* Alarm is disabled when this list is empty.
|
||||||
*/
|
*/
|
||||||
private List<BluetoothDevice> mDevicesWithAlarm;
|
private List<BluetoothDevice> devicesWithAlarm;
|
||||||
|
|
||||||
private int mAttempt;
|
|
||||||
private final static int MAX_ATTEMPTS = 1;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This local binder is an interface for the bonded activity to operate with the proximity
|
* This local binder is an interface for the bonded activity to operate with the proximity
|
||||||
* sensor.
|
* sensor.
|
||||||
*/
|
*/
|
||||||
public class ProximityBinder extends LocalBinder {
|
class ProximityBinder extends LocalBinder {
|
||||||
/**
|
/**
|
||||||
* Toggles the Immediate Alert on given remote device.
|
* Toggles the Immediate Alert on given remote device.
|
||||||
*
|
*
|
||||||
* @param device the connected device.
|
* @param device the connected device.
|
||||||
*/
|
*/
|
||||||
public void toggleImmediateAlert(final BluetoothDevice device) {
|
void toggleImmediateAlert(final BluetoothDevice device) {
|
||||||
final ProximityManager manager = (ProximityManager) getBleManager(device);
|
final ProximityManager manager = (ProximityManager) getBleManager(device);
|
||||||
manager.toggleImmediateAlert();
|
manager.toggleImmediateAlert();
|
||||||
}
|
}
|
||||||
@@ -110,7 +108,7 @@ public class ProximityService extends BleMulticonnectProfileService implements P
|
|||||||
* @param device the connected device.
|
* @param device the connected device.
|
||||||
* @return True if alarm has been enabled, false if disabled.
|
* @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);
|
final ProximityManager manager = (ProximityManager) getBleManager(device);
|
||||||
return manager.isAlertEnabled();
|
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
|
* @return Battery value or null if no value was received or Battery Level characteristic
|
||||||
* was not found, or the device is disconnected.
|
* 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);
|
final ProximityManager manager = (ProximityManager) getBleManager(device);
|
||||||
return manager.getBatteryLevel();
|
return manager.getBatteryLevel();
|
||||||
}
|
}
|
||||||
@@ -130,24 +128,31 @@ public class ProximityService extends BleMulticonnectProfileService implements P
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected LocalBinder getBinder() {
|
protected LocalBinder getBinder() {
|
||||||
return mBinder;
|
return binder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected LoggableBleManager<ProximityManagerCallbacks> initializeManager() {
|
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
|
* This broadcast receiver listens for {@link #ACTION_DISCONNECT} that may be fired by pressing
|
||||||
* Disconnect action button on the notification.
|
* Disconnect action button on the notification.
|
||||||
*/
|
*/
|
||||||
private final BroadcastReceiver mDisconnectActionBroadcastReceiver = new BroadcastReceiver() {
|
private final BroadcastReceiver disconnectActionBroadcastReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(final Context context, final Intent intent) {
|
public void onReceive(final Context context, final Intent intent) {
|
||||||
final BluetoothDevice device = intent.getParcelableExtra(EXTRA_DEVICE);
|
final BluetoothDevice device = intent.getParcelableExtra(EXTRA_DEVICE);
|
||||||
mBinder.log(device, LogContract.Log.Level.INFO, "[Notification] DISCONNECT action pressed");
|
binder.log(device, LogContract.Log.Level.INFO, "[Notification] DISCONNECT action pressed");
|
||||||
mBinder.disconnect(device);
|
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
|
* 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.
|
* be fired by pressing Find me action button on the notification.
|
||||||
*/
|
*/
|
||||||
private final BroadcastReceiver mToggleAlarmActionBroadcastReceiver = new BroadcastReceiver() {
|
private final BroadcastReceiver toggleAlarmActionBroadcastReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(final Context context, final Intent intent) {
|
public void onReceive(final Context context, final Intent intent) {
|
||||||
final BluetoothDevice device = intent.getParcelableExtra(EXTRA_DEVICE);
|
final BluetoothDevice device = intent.getParcelableExtra(EXTRA_DEVICE);
|
||||||
switch (intent.getAction()) {
|
switch (intent.getAction()) {
|
||||||
case ACTION_FIND:
|
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;
|
break;
|
||||||
case ACTION_SILENT:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
mBinder.toggleImmediateAlert(device);
|
binder.toggleImmediateAlert(device);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onServiceCreated() {
|
protected void onServiceCreated() {
|
||||||
mServerManager = new ProximityServerManager(this);
|
serverManager = new ProximityServerManager(this);
|
||||||
mServerManager.setLogger(mBinder);
|
serverManager.setManagerCallbacks(this);
|
||||||
|
|
||||||
initializeAlarm();
|
initializeAlarm();
|
||||||
|
|
||||||
registerReceiver(mDisconnectActionBroadcastReceiver, new IntentFilter(ACTION_DISCONNECT));
|
registerReceiver(disconnectActionBroadcastReceiver, new IntentFilter(ACTION_DISCONNECT));
|
||||||
final IntentFilter filter = new IntentFilter();
|
final IntentFilter filter = new IntentFilter();
|
||||||
filter.addAction(ACTION_FIND);
|
filter.addAction(ACTION_FIND);
|
||||||
filter.addAction(ACTION_SILENT);
|
filter.addAction(ACTION_SILENT);
|
||||||
registerReceiver(mToggleAlarmActionBroadcastReceiver, filter);
|
registerReceiver(toggleAlarmActionBroadcastReceiver, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -190,55 +195,34 @@ public class ProximityService extends BleMulticonnectProfileService implements P
|
|||||||
cancelNotifications();
|
cancelNotifications();
|
||||||
|
|
||||||
// Close the GATT server. If it hasn't been opened this method does nothing
|
// Close the GATT server. If it hasn't been opened this method does nothing
|
||||||
mServerManager.closeGattServer();
|
serverManager.close();
|
||||||
|
serverManager = null;
|
||||||
|
|
||||||
releaseAlarm();
|
releaseAlarm();
|
||||||
|
|
||||||
unregisterReceiver(mDisconnectActionBroadcastReceiver);
|
unregisterReceiver(disconnectActionBroadcastReceiver);
|
||||||
unregisterReceiver(mToggleAlarmActionBroadcastReceiver);
|
unregisterReceiver(toggleAlarmActionBroadcastReceiver);
|
||||||
|
|
||||||
super.onServiceStopped();
|
super.onServiceStopped();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onBluetoothEnabled() {
|
protected void onBluetoothEnabled() {
|
||||||
mAttempt = 0;
|
// First, open the server. onServerReady() will be called when all services were added.
|
||||||
getHandler().post(new Runnable() {
|
serverManager.open();
|
||||||
@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();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onGattServerFailed(final int error) {
|
public void onServerReady() {
|
||||||
mServerManager.closeGattServer();
|
// This will start reconnecting to devices that will previously connected.
|
||||||
|
super.onBluetoothEnabled();
|
||||||
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
|
@Override
|
||||||
protected void onBluetoothDisabled() {
|
protected void onBluetoothDisabled() {
|
||||||
super.onBluetoothDisabled();
|
super.onBluetoothDisabled();
|
||||||
// Close the GATT server
|
// Close the GATT server
|
||||||
mServerManager.closeGattServer();
|
serverManager.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -270,27 +254,25 @@ public class ProximityService extends BleMulticonnectProfileService implements P
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceConnected(final BluetoothDevice device) {
|
public void onDeviceConnected(@NonNull final BluetoothDevice device) {
|
||||||
super.onDeviceConnected(device);
|
super.onDeviceConnected(device);
|
||||||
|
|
||||||
if (!mBound) {
|
if (!bound) {
|
||||||
createBackgroundNotification();
|
createBackgroundNotification();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) {
|
public void onDeviceConnectedToServer(@NonNull final BluetoothDevice device) {
|
||||||
super.onServicesDiscovered(device, optionalServicesFound);
|
binder.log(Log.INFO, device.getAddress() + " connected to server");
|
||||||
mServerManager.openConnection(device);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLinkLossOccurred(final BluetoothDevice device) {
|
public void onLinkLossOccurred(@NonNull final BluetoothDevice device) {
|
||||||
mServerManager.cancelConnection(device);
|
|
||||||
stopAlarm(device);
|
stopAlarm(device);
|
||||||
super.onLinkLossOccurred(device);
|
super.onLinkLossOccurred(device);
|
||||||
|
|
||||||
if (!mBound) {
|
if (!bound) {
|
||||||
createBackgroundNotification();
|
createBackgroundNotification();
|
||||||
if (BluetoothAdapter.getDefaultAdapter().isEnabled())
|
if (BluetoothAdapter.getDefaultAdapter().isEnabled())
|
||||||
createLinkLossNotification(device);
|
createLinkLossNotification(device);
|
||||||
@@ -300,25 +282,19 @@ public class ProximityService extends BleMulticonnectProfileService implements P
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceDisconnected(final BluetoothDevice device) {
|
public void onDeviceDisconnected(@NonNull final BluetoothDevice device) {
|
||||||
mServerManager.cancelConnection(device);
|
|
||||||
stopAlarm(device);
|
stopAlarm(device);
|
||||||
super.onDeviceDisconnected(device);
|
super.onDeviceDisconnected(device);
|
||||||
|
|
||||||
if (!mBound) {
|
if (!bound) {
|
||||||
cancelNotification(device);
|
cancelNotification(device);
|
||||||
createBackgroundNotification();
|
createBackgroundNotification();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAlarmTriggered(@NonNull final BluetoothDevice device) {
|
public void onDeviceDisconnectedFromServer(@NonNull final BluetoothDevice device) {
|
||||||
playAlarm(device);
|
binder.log(Log.INFO, device.getAddress() + " disconnected from server");
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAlarmStopped(@NonNull final BluetoothDevice device) {
|
|
||||||
stopAlarm(device);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -328,11 +304,19 @@ public class ProximityService extends BleMulticonnectProfileService implements P
|
|||||||
broadcast.putExtra(EXTRA_ALARM_STATE, on);
|
broadcast.putExtra(EXTRA_ALARM_STATE, on);
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||||
|
|
||||||
if (!mBound) {
|
if (!bound) {
|
||||||
createBackgroundNotification();
|
createBackgroundNotification();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLocalAlarmSwitched(@NonNull final BluetoothDevice device, final boolean on) {
|
||||||
|
if (on)
|
||||||
|
playAlarm(device);
|
||||||
|
else
|
||||||
|
stopAlarm(device);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) {
|
public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) {
|
||||||
final Intent broadcast = new Intent(BROADCAST_BATTERY_LEVEL);
|
final Intent broadcast = new Intent(BROADCAST_BATTERY_LEVEL);
|
||||||
@@ -537,36 +521,36 @@ public class ProximityService extends BleMulticonnectProfileService implements P
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void initializeAlarm() {
|
private void initializeAlarm() {
|
||||||
mDevicesWithAlarm = new LinkedList<>();
|
devicesWithAlarm = new LinkedList<>();
|
||||||
mMediaPlayer = new MediaPlayer();
|
mediaPlayer = new MediaPlayer();
|
||||||
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
|
mediaPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
|
||||||
mMediaPlayer.setLooping(true);
|
mediaPlayer.setLooping(true);
|
||||||
mMediaPlayer.setVolume(1.0f, 1.0f);
|
mediaPlayer.setVolume(1.0f, 1.0f);
|
||||||
try {
|
try {
|
||||||
mMediaPlayer.setDataSource(this, RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM));
|
mediaPlayer.setDataSource(this, RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM));
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
Log.e(TAG, "Initialize Alarm failed: ", e);
|
Log.e(TAG, "Initialize Alarm failed: ", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void releaseAlarm() {
|
private void releaseAlarm() {
|
||||||
mMediaPlayer.release();
|
mediaPlayer.release();
|
||||||
mMediaPlayer = null;
|
mediaPlayer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void playAlarm(final BluetoothDevice device) {
|
private void playAlarm(final BluetoothDevice device) {
|
||||||
final boolean alarmPlaying = !mDevicesWithAlarm.isEmpty();
|
final boolean alarmPlaying = !devicesWithAlarm.isEmpty();
|
||||||
if (!mDevicesWithAlarm.contains(device))
|
if (!devicesWithAlarm.contains(device))
|
||||||
mDevicesWithAlarm.add(device);
|
devicesWithAlarm.add(device);
|
||||||
|
|
||||||
if (!alarmPlaying) {
|
if (!alarmPlaying) {
|
||||||
// Save the current alarm volume and set it to max
|
// Save the current alarm volume and set it to max
|
||||||
final AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
|
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);
|
am.setStreamVolume(AudioManager.STREAM_ALARM, am.getStreamMaxVolume(AudioManager.STREAM_ALARM), AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
|
||||||
try {
|
try {
|
||||||
mMediaPlayer.prepare();
|
mediaPlayer.prepare();
|
||||||
mMediaPlayer.start();
|
mediaPlayer.start();
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
Log.e(TAG, "Prepare Alarm failed: ", 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) {
|
private void stopAlarm(final BluetoothDevice device) {
|
||||||
mDevicesWithAlarm.remove(device);
|
devicesWithAlarm.remove(device);
|
||||||
if (mDevicesWithAlarm.isEmpty() && mMediaPlayer.isPlaying()) {
|
if (devicesWithAlarm.isEmpty() && mediaPlayer.isPlaying()) {
|
||||||
mMediaPlayer.stop();
|
mediaPlayer.stop();
|
||||||
// Restore original volume
|
// Restore original volume
|
||||||
final AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
|
final AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
|
||||||
am.setStreamVolume(AudioManager.STREAM_ALARM, mOriginalVolume, 0);
|
am.setStreamVolume(AudioManager.STREAM_ALARM, originalVolume, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ import android.content.IntentFilter;
|
|||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
@@ -44,16 +46,16 @@ import no.nordicsemi.android.nrftoolbox.rsc.settings.SettingsActivity;
|
|||||||
import no.nordicsemi.android.nrftoolbox.rsc.settings.SettingsFragment;
|
import no.nordicsemi.android.nrftoolbox.rsc.settings.SettingsFragment;
|
||||||
|
|
||||||
public class RSCActivity extends BleProfileServiceReadyActivity<RSCService.RSCBinder> {
|
public class RSCActivity extends BleProfileServiceReadyActivity<RSCService.RSCBinder> {
|
||||||
private TextView mSpeedView;
|
private TextView speedView;
|
||||||
private TextView mSpeedUnitView;
|
private TextView speedUnitView;
|
||||||
private TextView mCadenceView;
|
private TextView cadenceView;
|
||||||
private TextView mDistanceView;
|
private TextView distanceView;
|
||||||
private TextView mDistanceUnitView;
|
private TextView distanceUnitView;
|
||||||
private TextView mTotalDistanceView;
|
private TextView totalDistanceView;
|
||||||
private TextView mTotalDistanceUnitView;
|
private TextView totalDistanceUnitView;
|
||||||
private TextView mStridesCountView;
|
private TextView stridesCountView;
|
||||||
private TextView mActivityView;
|
private TextView activityView;
|
||||||
private TextView mBatteryLevelView;
|
private TextView batteryLevelView;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreateView(final Bundle savedInstanceState) {
|
protected void onCreateView(final Bundle savedInstanceState) {
|
||||||
@@ -63,26 +65,26 @@ public class RSCActivity extends BleProfileServiceReadyActivity<RSCService.RSCBi
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onInitialize(final Bundle savedInstanceState) {
|
protected void onInitialize(final Bundle savedInstanceState) {
|
||||||
LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, makeIntentFilter());
|
LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, makeIntentFilter());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver);
|
LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setGui() {
|
private void setGui() {
|
||||||
mSpeedView = findViewById(R.id.speed);
|
speedView = findViewById(R.id.speed);
|
||||||
mSpeedUnitView = findViewById(R.id.speed_unit);
|
speedUnitView = findViewById(R.id.speed_unit);
|
||||||
mCadenceView = findViewById(R.id.cadence);
|
cadenceView = findViewById(R.id.cadence);
|
||||||
mDistanceView = findViewById(R.id.distance);
|
distanceView = findViewById(R.id.distance);
|
||||||
mDistanceUnitView = findViewById(R.id.distance_unit);
|
distanceUnitView = findViewById(R.id.distance_unit);
|
||||||
mTotalDistanceView = findViewById(R.id.total_distance);
|
totalDistanceView = findViewById(R.id.total_distance);
|
||||||
mTotalDistanceUnitView = findViewById(R.id.total_distance_unit);
|
totalDistanceUnitView = findViewById(R.id.total_distance_unit);
|
||||||
mStridesCountView = findViewById(R.id.strides);
|
stridesCountView = findViewById(R.id.strides);
|
||||||
mActivityView = findViewById(R.id.activity);
|
activityView = findViewById(R.id.activity);
|
||||||
mBatteryLevelView = findViewById(R.id.battery);
|
batteryLevelView = findViewById(R.id.battery);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -93,13 +95,13 @@ public class RSCActivity extends BleProfileServiceReadyActivity<RSCService.RSCBi
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setDefaultUI() {
|
protected void setDefaultUI() {
|
||||||
mSpeedView.setText(R.string.not_available_value);
|
speedView.setText(R.string.not_available_value);
|
||||||
mCadenceView.setText(R.string.not_available_value);
|
cadenceView.setText(R.string.not_available_value);
|
||||||
mDistanceView.setText(R.string.not_available_value);
|
distanceView.setText(R.string.not_available_value);
|
||||||
mTotalDistanceView.setText(R.string.not_available_value);
|
totalDistanceView.setText(R.string.not_available_value);
|
||||||
mStridesCountView.setText(R.string.not_available_value);
|
stridesCountView.setText(R.string.not_available_value);
|
||||||
mActivityView.setText(R.string.not_available);
|
activityView.setText(R.string.not_available);
|
||||||
mBatteryLevelView.setText(R.string.not_available);
|
batteryLevelView.setText(R.string.not_available);
|
||||||
|
|
||||||
setUnits();
|
setUnits();
|
||||||
}
|
}
|
||||||
@@ -110,19 +112,19 @@ public class RSCActivity extends BleProfileServiceReadyActivity<RSCService.RSCBi
|
|||||||
|
|
||||||
switch (unit) {
|
switch (unit) {
|
||||||
case SettingsFragment.SETTINGS_UNIT_M_S: // [m/s]
|
case SettingsFragment.SETTINGS_UNIT_M_S: // [m/s]
|
||||||
mSpeedUnitView.setText(R.string.rsc_speed_unit_m_s);
|
speedUnitView.setText(R.string.rsc_speed_unit_m_s);
|
||||||
mDistanceUnitView.setText(R.string.rsc_distance_unit_m);
|
distanceUnitView.setText(R.string.rsc_distance_unit_m);
|
||||||
mTotalDistanceUnitView.setText(R.string.rsc_total_distance_unit_km);
|
totalDistanceUnitView.setText(R.string.rsc_total_distance_unit_km);
|
||||||
break;
|
break;
|
||||||
case SettingsFragment.SETTINGS_UNIT_KM_H: // [km/h]
|
case SettingsFragment.SETTINGS_UNIT_KM_H: // [km/h]
|
||||||
mSpeedUnitView.setText(R.string.rsc_speed_unit_km_h);
|
speedUnitView.setText(R.string.rsc_speed_unit_km_h);
|
||||||
mDistanceUnitView.setText(R.string.rsc_distance_unit_m);
|
distanceUnitView.setText(R.string.rsc_distance_unit_m);
|
||||||
mTotalDistanceUnitView.setText(R.string.rsc_total_distance_unit_km);
|
totalDistanceUnitView.setText(R.string.rsc_total_distance_unit_km);
|
||||||
break;
|
break;
|
||||||
case SettingsFragment.SETTINGS_UNIT_MPH: // [mph]
|
case SettingsFragment.SETTINGS_UNIT_MPH: // [mph]
|
||||||
mSpeedUnitView.setText(R.string.rsc_speed_unit_mph);
|
speedUnitView.setText(R.string.rsc_speed_unit_mph);
|
||||||
mDistanceUnitView.setText(R.string.rsc_distance_unit_yd);
|
distanceUnitView.setText(R.string.rsc_distance_unit_yd);
|
||||||
mTotalDistanceUnitView.setText(R.string.rsc_total_distance_unit_mile);
|
totalDistanceUnitView.setText(R.string.rsc_total_distance_unit_mile);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -180,14 +182,14 @@ public class RSCActivity extends BleProfileServiceReadyActivity<RSCService.RSCBi
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) {
|
public void onServicesDiscovered(@NonNull final BluetoothDevice device, final boolean optionalServicesFound) {
|
||||||
// not used
|
// not used
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceDisconnected(final BluetoothDevice device) {
|
public void onDeviceDisconnected(@NonNull final BluetoothDevice device) {
|
||||||
super.onDeviceDisconnected(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) {
|
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
|
// pass through intended
|
||||||
case SettingsFragment.SETTINGS_UNIT_M_S:
|
case SettingsFragment.SETTINGS_UNIT_M_S:
|
||||||
if (totalDistance == -1) {
|
if (totalDistance == -1) {
|
||||||
mTotalDistanceView.setText(R.string.not_available);
|
totalDistanceView.setText(R.string.not_available);
|
||||||
mTotalDistanceUnitView.setText(null);
|
totalDistanceUnitView.setText(null);
|
||||||
} else {
|
} else {
|
||||||
mTotalDistanceView.setText(String.format(Locale.US, "%.2f", totalDistance / 1000.0f)); // 1 km in m
|
totalDistanceView.setText(String.format(Locale.US, "%.2f", totalDistance / 1000.0f)); // 1 km in m
|
||||||
mTotalDistanceUnitView.setText(R.string.rsc_total_distance_unit_km);
|
totalDistanceUnitView.setText(R.string.rsc_total_distance_unit_km);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SettingsFragment.SETTINGS_UNIT_MPH:
|
case SettingsFragment.SETTINGS_UNIT_MPH:
|
||||||
speed = speed * 2.2369f;
|
speed = speed * 2.2369f;
|
||||||
if (totalDistance == -1) {
|
if (totalDistance == -1) {
|
||||||
mTotalDistanceView.setText(R.string.not_available);
|
totalDistanceView.setText(R.string.not_available);
|
||||||
mTotalDistanceUnitView.setText(null);
|
totalDistanceUnitView.setText(null);
|
||||||
} else {
|
} else {
|
||||||
mTotalDistanceView.setText(String.format(Locale.US, "%.2f", totalDistance / 1609.31f)); // 1 mile in m
|
totalDistanceView.setText(String.format(Locale.US, "%.2f", totalDistance / 1609.31f)); // 1 mile in m
|
||||||
mTotalDistanceUnitView.setText(R.string.rsc_total_distance_unit_mile);
|
totalDistanceUnitView.setText(R.string.rsc_total_distance_unit_mile);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
mSpeedView.setText(String.format(Locale.US, "%.1f", speed));
|
speedView.setText(String.format(Locale.US, "%.1f", speed));
|
||||||
mCadenceView.setText(String.format(Locale.US, "%d", cadence));
|
cadenceView.setText(String.format(Locale.US, "%d", cadence));
|
||||||
mActivityView.setText(running ? R.string.rsc_running : R.string.rsc_walking);
|
activityView.setText(running ? R.string.rsc_running : R.string.rsc_walking);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onStripesUpdate(final long distance, final int strides) {
|
private void onStripesUpdate(final long distance, final int strides) {
|
||||||
if (distance == -1) {
|
if (distance == -1) {
|
||||||
mDistanceView.setText(R.string.not_available);
|
distanceView.setText(R.string.not_available);
|
||||||
mDistanceUnitView.setText(R.string.rsc_distance_unit_m);
|
distanceUnitView.setText(R.string.rsc_distance_unit_m);
|
||||||
} else {
|
} else {
|
||||||
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
|
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
final int unit = Integer.parseInt(preferences.getString(SettingsFragment.SETTINGS_UNIT, String.valueOf(SettingsFragment.SETTINGS_UNIT_DEFAULT)));
|
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_KM_H:
|
||||||
case SettingsFragment.SETTINGS_UNIT_M_S:
|
case SettingsFragment.SETTINGS_UNIT_M_S:
|
||||||
if (distance < 100000L) { // 1 km in cm
|
if (distance < 100000L) { // 1 km in cm
|
||||||
mDistanceView.setText(String.format(Locale.US, "%.1f", distance / 100.0f));
|
distanceView.setText(String.format(Locale.US, "%.1f", distance / 100.0f));
|
||||||
mDistanceUnitView.setText(R.string.rsc_distance_unit_m);
|
distanceUnitView.setText(R.string.rsc_distance_unit_m);
|
||||||
} else {
|
} else {
|
||||||
mDistanceView.setText(String.format(Locale.US, "%.2f", distance / 100000.0f));
|
distanceView.setText(String.format(Locale.US, "%.2f", distance / 100000.0f));
|
||||||
mDistanceUnitView.setText(R.string.rsc_distance_unit_km);
|
distanceUnitView.setText(R.string.rsc_distance_unit_km);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SettingsFragment.SETTINGS_UNIT_MPH:
|
case SettingsFragment.SETTINGS_UNIT_MPH:
|
||||||
if (distance < 160931L) { // 1 mile in cm
|
if (distance < 160931L) { // 1 mile in cm
|
||||||
mDistanceView.setText(String.format(Locale.US, "%.1f", distance / 91.4392f));
|
distanceView.setText(String.format(Locale.US, "%.1f", distance / 91.4392f));
|
||||||
mDistanceUnitView.setText(R.string.rsc_distance_unit_yd);
|
distanceUnitView.setText(R.string.rsc_distance_unit_yd);
|
||||||
} else {
|
} else {
|
||||||
mDistanceView.setText(String.format(Locale.US, "%.2f", distance / 160931.23f));
|
distanceView.setText(String.format(Locale.US, "%.2f", distance / 160931.23f));
|
||||||
mDistanceUnitView.setText(R.string.rsc_distance_unit_mile);
|
distanceUnitView.setText(R.string.rsc_distance_unit_mile);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mStridesCountView.setText(String.valueOf(strides));
|
stridesCountView.setText(String.valueOf(strides));
|
||||||
}
|
}
|
||||||
|
|
||||||
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
|
private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(final Context context, final Intent intent) {
|
public void onReceive(final Context context, final Intent intent) {
|
||||||
final String action = intent.getAction();
|
final String action = intent.getAction();
|
||||||
|
|||||||
@@ -40,11 +40,11 @@ import no.nordicsemi.android.nrftoolbox.parser.RSCMeasurementParser;
|
|||||||
|
|
||||||
public class RSCManager extends BatteryManager<RSCManagerCallbacks> {
|
public class RSCManager extends BatteryManager<RSCManagerCallbacks> {
|
||||||
/** Running Speed and Cadence Measurement service UUID */
|
/** 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 */
|
/** Running Speed and Cadence Measurement characteristic UUID */
|
||||||
private static final UUID RSC_MEASUREMENT_CHARACTERISTIC_UUID = UUID.fromString("00002A53-0000-1000-8000-00805f9b34fb");
|
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) {
|
RSCManager(final Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
@@ -53,19 +53,19 @@ public class RSCManager extends BatteryManager<RSCManagerCallbacks> {
|
|||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
protected BatteryManagerGattCallback getGattCallback() {
|
protected BatteryManagerGattCallback getGattCallback() {
|
||||||
return mGattCallback;
|
return gattCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BluetoothGatt callbacks for connection/disconnection, service discovery,
|
* BluetoothGatt callbacks for connection/disconnection, service discovery,
|
||||||
* receiving indication, etc.
|
* receiving indication, etc.
|
||||||
*/
|
*/
|
||||||
private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() {
|
private final BatteryManagerGattCallback gattCallback = new BatteryManagerGattCallback() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initialize() {
|
protected void initialize() {
|
||||||
super.initialize();
|
super.initialize();
|
||||||
setNotificationCallback(mRSCMeasurementCharacteristic)
|
setNotificationCallback(rscMeasurementCharacteristic)
|
||||||
.with(new RunningSpeedAndCadenceMeasurementDataCallback() {
|
.with(new RunningSpeedAndCadenceMeasurementDataCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
|
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,
|
final float instantaneousSpeed, final int instantaneousCadence,
|
||||||
@Nullable final Integer strideLength,
|
@Nullable final Integer strideLength,
|
||||||
@Nullable final Long totalDistance) {
|
@Nullable final Long totalDistance) {
|
||||||
mCallbacks.onRSCMeasurementReceived(device, running, instantaneousSpeed,
|
callbacks.onRSCMeasurementReceived(device, running, instantaneousSpeed,
|
||||||
instantaneousCadence, strideLength, totalDistance);
|
instantaneousCadence, strideLength, totalDistance);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
enableNotifications(mRSCMeasurementCharacteristic).enqueue();
|
enableNotifications(rscMeasurementCharacteristic).enqueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) {
|
public boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) {
|
||||||
final BluetoothGattService service = gatt.getService(RUNNING_SPEED_AND_CADENCE_SERVICE_UUID);
|
final BluetoothGattService service = gatt.getService(RUNNING_SPEED_AND_CADENCE_SERVICE_UUID);
|
||||||
if (service != null) {
|
if (service != null) {
|
||||||
mRSCMeasurementCharacteristic = service.getCharacteristic(RSC_MEASUREMENT_CHARACTERISTIC_UUID);
|
rscMeasurementCharacteristic = service.getCharacteristic(RSC_MEASUREMENT_CHARACTERISTIC_UUID);
|
||||||
}
|
}
|
||||||
return mRSCMeasurementCharacteristic != null;
|
return rscMeasurementCharacteristic != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDeviceDisconnected() {
|
protected void onDeviceDisconnected() {
|
||||||
super.onDeviceDisconnected();
|
super.onDeviceDisconnected();
|
||||||
mRSCMeasurementCharacteristic = null;
|
rscMeasurementCharacteristic = null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import no.nordicsemi.android.nrftoolbox.profile.BleProfileService;
|
|||||||
import no.nordicsemi.android.nrftoolbox.profile.LoggableBleManager;
|
import no.nordicsemi.android.nrftoolbox.profile.LoggableBleManager;
|
||||||
|
|
||||||
public class RSCService extends BleProfileService implements RSCManagerCallbacks {
|
public class RSCService extends BleProfileService implements RSCManagerCallbacks {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
private static final String TAG = "RSCService";
|
private static final String TAG = "RSCService";
|
||||||
|
|
||||||
public static final String BROADCAST_RSC_MEASUREMENT = "no.nordicsemi.android.nrftoolbox.rsc.BROADCAST_RSC_MEASUREMENT";
|
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 final static String ACTION_DISCONNECT = "no.nordicsemi.android.nrftoolbox.rsc.ACTION_DISCONNECT";
|
||||||
|
|
||||||
private RSCManager mManager;
|
private RSCManager manager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The last value of a cadence
|
* The last value of a cadence
|
||||||
*/
|
*/
|
||||||
private float mCadence;
|
private float cadence;
|
||||||
/**
|
/**
|
||||||
* Trip distance in cm
|
* Trip distance in cm
|
||||||
*/
|
*/
|
||||||
private long mDistance;
|
private long distance;
|
||||||
/**
|
/**
|
||||||
* Stride length in cm
|
* Stride length in cm
|
||||||
*/
|
*/
|
||||||
private Integer mStrideLength;
|
private Integer strideLength;
|
||||||
/**
|
/**
|
||||||
* Number of steps in the trip
|
* Number of steps in the trip
|
||||||
*/
|
*/
|
||||||
private int mStepsNumber;
|
private int stepsNumber;
|
||||||
private boolean mTaskInProgress;
|
private boolean taskInProgress;
|
||||||
private final Handler mHandler = new Handler();
|
private final Handler handler = new Handler();
|
||||||
|
|
||||||
private final static int NOTIFICATION_ID = 200;
|
private final static int NOTIFICATION_ID = 200;
|
||||||
private final static int OPEN_ACTIVITY_REQ = 0;
|
private final static int OPEN_ACTIVITY_REQ = 0;
|
||||||
private final static int DISCONNECT_REQ = 1;
|
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.
|
* 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
|
@Override
|
||||||
protected LocalBinder getBinder() {
|
protected LocalBinder getBinder() {
|
||||||
return mBinder;
|
return binder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected LoggableBleManager<RSCManagerCallbacks> initializeManager() {
|
protected LoggableBleManager<RSCManagerCallbacks> initializeManager() {
|
||||||
return mManager = new RSCManager(this);
|
return manager = new RSCManager(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -113,14 +114,14 @@ public class RSCService extends BleProfileService implements RSCManagerCallbacks
|
|||||||
|
|
||||||
final IntentFilter filter = new IntentFilter();
|
final IntentFilter filter = new IntentFilter();
|
||||||
filter.addAction(ACTION_DISCONNECT);
|
filter.addAction(ACTION_DISCONNECT);
|
||||||
registerReceiver(mDisconnectActionBroadcastReceiver, filter);
|
registerReceiver(disconnectActionBroadcastReceiver, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
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
|
// when user has disconnected from the sensor, we have to cancel the notification that we've created some milliseconds before using unbindService
|
||||||
stopForegroundService();
|
stopForegroundService();
|
||||||
unregisterReceiver(mDisconnectActionBroadcastReceiver);
|
unregisterReceiver(disconnectActionBroadcastReceiver);
|
||||||
|
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
}
|
}
|
||||||
@@ -132,7 +133,7 @@ public class RSCService extends BleProfileService implements RSCManagerCallbacks
|
|||||||
if (isConnected()) {
|
if (isConnected()) {
|
||||||
// This method will read the Battery Level value, if possible and then try to enable battery notifications (if it has NOTIFY property).
|
// 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.
|
// 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.
|
// 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.
|
// But we will still be receiving other values, if enabled.
|
||||||
if (isConnected())
|
if (isConnected())
|
||||||
mManager.disableBatteryLevelCharacteristicNotifications();
|
manager.disableBatteryLevelCharacteristicNotifications();
|
||||||
|
|
||||||
startForegroundService();
|
startForegroundService();
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Runnable mUpdateStridesTask = new Runnable() {
|
private final Runnable updateStridesTask = new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (!isConnected())
|
if (!isConnected())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mStepsNumber++;
|
stepsNumber++;
|
||||||
mDistance += mStrideLength; // [cm]
|
distance += strideLength; // [cm]
|
||||||
final Intent broadcast = new Intent(BROADCAST_STRIDES_UPDATE);
|
final Intent broadcast = new Intent(BROADCAST_STRIDES_UPDATE);
|
||||||
broadcast.putExtra(EXTRA_STRIDES, mStepsNumber);
|
broadcast.putExtra(EXTRA_STRIDES, stepsNumber);
|
||||||
broadcast.putExtra(EXTRA_DISTANCE, mDistance);
|
broadcast.putExtra(EXTRA_DISTANCE, distance);
|
||||||
LocalBroadcastManager.getInstance(RSCService.this).sendBroadcast(broadcast);
|
LocalBroadcastManager.getInstance(RSCService.this).sendBroadcast(broadcast);
|
||||||
|
|
||||||
if (mCadence > 0) {
|
if (cadence > 0) {
|
||||||
final long interval = (long) (1000.0f * 60.0f / mCadence);
|
final long interval = (long) (1000.0f * 60.0f / cadence);
|
||||||
mHandler.postDelayed(mUpdateStridesTask, interval);
|
handler.postDelayed(updateStridesTask, interval);
|
||||||
} else {
|
} else {
|
||||||
mTaskInProgress = false;
|
taskInProgress = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -183,15 +184,15 @@ public class RSCService extends BleProfileService implements RSCManagerCallbacks
|
|||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||||
|
|
||||||
// Start strides counter if not in progress
|
// Start strides counter if not in progress
|
||||||
mCadence = instantaneousCadence;
|
cadence = instantaneousCadence;
|
||||||
if (strideLength != null) {
|
if (strideLength != null) {
|
||||||
mStrideLength = strideLength;
|
this.strideLength = strideLength;
|
||||||
}
|
}
|
||||||
if (!mTaskInProgress && strideLength != null && instantaneousCadence > 0) {
|
if (!taskInProgress && strideLength != null && instantaneousCadence > 0) {
|
||||||
mTaskInProgress = true;
|
taskInProgress = true;
|
||||||
|
|
||||||
final long interval = (long) (1000.0f * 60.0f / mCadence);
|
final long interval = (long) (1000.0f * 60.0f / cadence);
|
||||||
mHandler.postDelayed(mUpdateStridesTask, interval);
|
handler.postDelayed(updateStridesTask, interval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -238,6 +239,7 @@ public class RSCService extends BleProfileService implements RSCManagerCallbacks
|
|||||||
* f.e. <code><string name="name">%s is connected</string></code>
|
* f.e. <code><string name="name">%s is connected</string></code>
|
||||||
* @param defaults
|
* @param defaults
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("SameParameterValue")
|
||||||
private Notification createNotification(final int messageResId, final int defaults) {
|
private Notification createNotification(final int messageResId, final int defaults) {
|
||||||
final Intent parentIntent = new Intent(this, FeaturesActivity.class);
|
final Intent parentIntent = new Intent(this, FeaturesActivity.class);
|
||||||
parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
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.
|
* 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
|
@Override
|
||||||
public void onReceive(final Context context, final Intent intent) {
|
public void onReceive(final Context context, final Intent intent) {
|
||||||
Logger.i(getLogSession(), "[Notification] Disconnect action pressed");
|
Logger.i(getLogSession(), "[Notification] Disconnect action pressed");
|
||||||
|
|||||||
@@ -22,7 +22,6 @@
|
|||||||
package no.nordicsemi.android.nrftoolbox.scanner;
|
package no.nordicsemi.android.nrftoolbox.scanner;
|
||||||
|
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.content.Context;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -34,33 +33,32 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import no.nordicsemi.android.nrftoolbox.R;
|
import no.nordicsemi.android.nrftoolbox.R;
|
||||||
import no.nordicsemi.android.support.v18.scanner.ScanResult;
|
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.
|
* 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_TITLE = 0;
|
||||||
private static final int TYPE_ITEM = 1;
|
private static final int TYPE_ITEM = 1;
|
||||||
private static final int TYPE_EMPTY = 2;
|
private static final int TYPE_EMPTY = 2;
|
||||||
|
|
||||||
private final ArrayList<ExtendedBluetoothDevice> mListBondedValues = new ArrayList<>();
|
private final ArrayList<ExtendedBluetoothDevice> listBondedValues = new ArrayList<>();
|
||||||
private final ArrayList<ExtendedBluetoothDevice> mListValues = new ArrayList<>();
|
private final ArrayList<ExtendedBluetoothDevice> listValues = new ArrayList<>();
|
||||||
private final Context mContext;
|
|
||||||
|
|
||||||
public DeviceListAdapter(final Context context) {
|
DeviceListAdapter() {
|
||||||
mContext = context;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a list of bonded devices.
|
* Sets a list of bonded devices.
|
||||||
* @param devices list of bonded devices.
|
* @param devices list of bonded devices.
|
||||||
*/
|
*/
|
||||||
public void addBondedDevices(final Set<BluetoothDevice> devices) {
|
void addBondedDevices(@NonNull final Set<BluetoothDevice> devices) {
|
||||||
final List<ExtendedBluetoothDevice> bondedDevices = mListBondedValues;
|
|
||||||
for (BluetoothDevice device : devices) {
|
for (BluetoothDevice device : devices) {
|
||||||
bondedDevices.add(new ExtendedBluetoothDevice(device));
|
listBondedValues.add(new ExtendedBluetoothDevice(device));
|
||||||
}
|
}
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
@@ -69,11 +67,11 @@ public class DeviceListAdapter extends BaseAdapter {
|
|||||||
* Updates the list of not bonded devices.
|
* Updates the list of not bonded devices.
|
||||||
* @param results list of results from the scanner
|
* @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) {
|
for (final ScanResult result : results) {
|
||||||
final ExtendedBluetoothDevice device = findDevice(result);
|
final ExtendedBluetoothDevice device = findDevice(result);
|
||||||
if (device == null) {
|
if (device == null) {
|
||||||
mListValues.add(new ExtendedBluetoothDevice(result));
|
listValues.add(new ExtendedBluetoothDevice(result));
|
||||||
} else {
|
} else {
|
||||||
device.name = result.getScanRecord() != null ? result.getScanRecord().getDeviceName() : null;
|
device.name = result.getScanRecord() != null ? result.getScanRecord().getDeviceName() : null;
|
||||||
device.rssi = result.getRssi();
|
device.rssi = result.getRssi();
|
||||||
@@ -82,46 +80,46 @@ public class DeviceListAdapter extends BaseAdapter {
|
|||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ExtendedBluetoothDevice findDevice(final ScanResult result) {
|
private ExtendedBluetoothDevice findDevice(@NonNull final ScanResult result) {
|
||||||
for (final ExtendedBluetoothDevice device : mListBondedValues)
|
for (final ExtendedBluetoothDevice device : listBondedValues)
|
||||||
if (device.matches(result))
|
if (device.matches(result))
|
||||||
return device;
|
return device;
|
||||||
for (final ExtendedBluetoothDevice device : mListValues)
|
for (final ExtendedBluetoothDevice device : listValues)
|
||||||
if (device.matches(result))
|
if (device.matches(result))
|
||||||
return device;
|
return device;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearDevices() {
|
void clearDevices() {
|
||||||
mListValues.clear();
|
listValues.clear();
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getCount() {
|
public int getCount() {
|
||||||
final int bondedCount = mListBondedValues.size() + 1; // 1 for the title
|
final int bondedCount = listBondedValues.size() + 1; // 1 for the title
|
||||||
final int availableCount = mListValues.isEmpty() ? 2 : mListValues.size() + 1; // 1 for title, 1 for empty text
|
final int availableCount = listValues.isEmpty() ? 2 : listValues.size() + 1; // 1 for title, 1 for empty text
|
||||||
if (bondedCount == 1)
|
if (bondedCount == 1)
|
||||||
return availableCount;
|
return availableCount;
|
||||||
return bondedCount + availableCount;
|
return bondedCount + availableCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getItem(int position) {
|
public Object getItem(final int position) {
|
||||||
final int bondedCount = mListBondedValues.size() + 1; // 1 for the title
|
final int bondedCount = listBondedValues.size() + 1; // 1 for the title
|
||||||
if (mListBondedValues.isEmpty()) {
|
if (listBondedValues.isEmpty()) {
|
||||||
if (position == 0)
|
if (position == 0)
|
||||||
return R.string.scanner_subtitle_not_bonded;
|
return R.string.scanner_subtitle_not_bonded;
|
||||||
else
|
else
|
||||||
return mListValues.get(position - 1);
|
return listValues.get(position - 1);
|
||||||
} else {
|
} else {
|
||||||
if (position == 0)
|
if (position == 0)
|
||||||
return R.string.scanner_subtitle_bonded;
|
return R.string.scanner_subtitle_bonded;
|
||||||
if (position < bondedCount)
|
if (position < bondedCount)
|
||||||
return mListBondedValues.get(position - 1);
|
return listBondedValues.get(position - 1);
|
||||||
if (position == bondedCount)
|
if (position == bondedCount)
|
||||||
return R.string.scanner_subtitle_not_bonded;
|
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
|
@Override
|
||||||
public boolean isEnabled(int position) {
|
public boolean isEnabled(final int position) {
|
||||||
return getItemViewType(position) == TYPE_ITEM;
|
return getItemViewType(position) == TYPE_ITEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getItemViewType(int position) {
|
public int getItemViewType(final int position) {
|
||||||
if (position == 0)
|
if (position == 0)
|
||||||
return TYPE_TITLE;
|
return TYPE_TITLE;
|
||||||
|
|
||||||
if (!mListBondedValues.isEmpty() && position == mListBondedValues.size() + 1)
|
if (!listBondedValues.isEmpty() && position == listBondedValues.size() + 1)
|
||||||
return TYPE_TITLE;
|
return TYPE_TITLE;
|
||||||
|
|
||||||
if (position == getCount() - 1 && mListValues.isEmpty())
|
if (position == getCount() - 1 && listValues.isEmpty())
|
||||||
return TYPE_EMPTY;
|
return TYPE_EMPTY;
|
||||||
|
|
||||||
return TYPE_ITEM;
|
return TYPE_ITEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getItemId(int position) {
|
public long getItemId(final int position) {
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View getView(int position, View oldView, ViewGroup parent) {
|
public View getView(final int position, @Nullable final View oldView, @NonNull final ViewGroup parent) {
|
||||||
final LayoutInflater inflater = LayoutInflater.from(mContext);
|
final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
|
||||||
final int type = getItemViewType(position);
|
final int type = getItemViewType(position);
|
||||||
|
|
||||||
View view = oldView;
|
View view = oldView;
|
||||||
@@ -191,7 +189,7 @@ public class DeviceListAdapter extends BaseAdapter {
|
|||||||
final ExtendedBluetoothDevice device = (ExtendedBluetoothDevice) getItem(position);
|
final ExtendedBluetoothDevice device = (ExtendedBluetoothDevice) getItem(position);
|
||||||
final ViewHolder holder = (ViewHolder) view.getTag();
|
final ViewHolder holder = (ViewHolder) view.getTag();
|
||||||
final String name = device.name;
|
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());
|
holder.address.setText(device.device.getAddress());
|
||||||
if (!device.isBonded || device.rssi != ExtendedBluetoothDevice.NO_RSSI) {
|
if (!device.isBonded || device.rssi != ExtendedBluetoothDevice.NO_RSSI) {
|
||||||
final int rssiPercent = (int) (100.0f * (127.0f + device.rssi) / (127.0f + 20.0f));
|
final int rssiPercent = (int) (100.0f * (127.0f + device.rssi) / (127.0f + 20.0f));
|
||||||
|
|||||||
@@ -23,8 +23,10 @@ package no.nordicsemi.android.nrftoolbox.scanner;
|
|||||||
|
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import no.nordicsemi.android.support.v18.scanner.ScanResult;
|
import no.nordicsemi.android.support.v18.scanner.ScanResult;
|
||||||
|
|
||||||
|
@SuppressWarnings("WeakerAccess")
|
||||||
public class ExtendedBluetoothDevice {
|
public class ExtendedBluetoothDevice {
|
||||||
/* package */ static final int NO_RSSI = -1000;
|
/* package */ static final int NO_RSSI = -1000;
|
||||||
public final BluetoothDevice device;
|
public final BluetoothDevice device;
|
||||||
@@ -33,21 +35,21 @@ public class ExtendedBluetoothDevice {
|
|||||||
public int rssi;
|
public int rssi;
|
||||||
public boolean isBonded;
|
public boolean isBonded;
|
||||||
|
|
||||||
public ExtendedBluetoothDevice(final ScanResult scanResult) {
|
public ExtendedBluetoothDevice(@NonNull final ScanResult scanResult) {
|
||||||
this.device = scanResult.getDevice();
|
this.device = scanResult.getDevice();
|
||||||
this.name = scanResult.getScanRecord() != null ? scanResult.getScanRecord().getDeviceName() : null;
|
this.name = scanResult.getScanRecord() != null ? scanResult.getScanRecord().getDeviceName() : null;
|
||||||
this.rssi = scanResult.getRssi();
|
this.rssi = scanResult.getRssi();
|
||||||
this.isBonded = false;
|
this.isBonded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ExtendedBluetoothDevice(final BluetoothDevice device) {
|
public ExtendedBluetoothDevice(@NonNull final BluetoothDevice device) {
|
||||||
this.device = device;
|
this.device = device;
|
||||||
this.name = device.getName();
|
this.name = device.getName();
|
||||||
this.rssi = NO_RSSI;
|
this.rssi = NO_RSSI;
|
||||||
this.isBonded = true;
|
this.isBonded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean matches(final ScanResult scanResult) {
|
public boolean matches(@NonNull final ScanResult scanResult) {
|
||||||
return device.getAddress().equals(scanResult.getDevice().getAddress());
|
return device.getAddress().equals(scanResult.getDevice().getAddress());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import android.os.Bundle;
|
|||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.ParcelUuid;
|
import android.os.ParcelUuid;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import androidx.core.app.ActivityCompat;
|
import androidx.core.app.ActivityCompat;
|
||||||
import androidx.fragment.app.DialogFragment;
|
import androidx.fragment.app.DialogFragment;
|
||||||
import androidx.core.content.ContextCompat;
|
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 final static int REQUEST_PERMISSION_REQ_CODE = 34; // any 8-bit number
|
||||||
|
|
||||||
private BluetoothAdapter mBluetoothAdapter;
|
private BluetoothAdapter bluetoothAdapter;
|
||||||
private OnDeviceSelectedListener mListener;
|
private OnDeviceSelectedListener listener;
|
||||||
private DeviceListAdapter mAdapter;
|
private DeviceListAdapter adapter;
|
||||||
private final Handler mHandler = new Handler();
|
private final Handler handler = new Handler();
|
||||||
private Button mScanButton;
|
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) {
|
public static ScannerFragment getInstance(final UUID uuid) {
|
||||||
final ScannerFragment fragment = new ScannerFragment();
|
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.
|
* 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.
|
* 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.
|
* 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.
|
* This will make sure that {@link OnDeviceSelectedListener} interface is implemented by activity.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(final Context context) {
|
public void onAttach(@NonNull final Context context) {
|
||||||
super.onAttach(context);
|
super.onAttach(context);
|
||||||
try {
|
try {
|
||||||
this.mListener = (OnDeviceSelectedListener) context;
|
this.listener = (OnDeviceSelectedListener) context;
|
||||||
} catch (final ClassCastException e) {
|
} catch (final ClassCastException e) {
|
||||||
throw new ClassCastException(context.toString() + " must implement OnDeviceSelectedListener");
|
throw new ClassCastException(context.toString() + " must implement OnDeviceSelectedListener");
|
||||||
}
|
}
|
||||||
@@ -133,12 +134,12 @@ public class ScannerFragment extends DialogFragment {
|
|||||||
|
|
||||||
final Bundle args = getArguments();
|
final Bundle args = getArguments();
|
||||||
if (args != null && args.containsKey(PARAM_UUID)) {
|
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);
|
final BluetoothManager manager = (BluetoothManager) requireContext().getSystemService(Context.BLUETOOTH_SERVICE);
|
||||||
if (manager != null) {
|
if (manager != null) {
|
||||||
mBluetoothAdapter = manager.getAdapter();
|
bluetoothAdapter = manager.getAdapter();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,27 +153,28 @@ public class ScannerFragment extends DialogFragment {
|
|||||||
@Override
|
@Override
|
||||||
public Dialog onCreateDialog(final Bundle savedInstanceState) {
|
public Dialog onCreateDialog(final Bundle savedInstanceState) {
|
||||||
final AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
|
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);
|
final ListView listview = dialogView.findViewById(android.R.id.list);
|
||||||
|
|
||||||
listview.setEmptyView(dialogView.findViewById(android.R.id.empty));
|
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);
|
builder.setTitle(R.string.scanner_title);
|
||||||
final AlertDialog dialog = builder.setView(dialogView).create();
|
final AlertDialog dialog = builder.setView(dialogView).create();
|
||||||
listview.setOnItemClickListener((parent, view, position, id) -> {
|
listview.setOnItemClickListener((parent, view, position, id) -> {
|
||||||
stopScan();
|
stopScan();
|
||||||
dialog.dismiss();
|
dialog.dismiss();
|
||||||
final ExtendedBluetoothDevice d = (ExtendedBluetoothDevice) mAdapter.getItem(position);
|
final ExtendedBluetoothDevice d = (ExtendedBluetoothDevice) adapter.getItem(position);
|
||||||
mListener.onDeviceSelected(d.device, d.name);
|
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);
|
scanButton = dialogView.findViewById(R.id.action_cancel);
|
||||||
mScanButton.setOnClickListener(v -> {
|
scanButton.setOnClickListener(v -> {
|
||||||
if (v.getId() == R.id.action_cancel) {
|
if (v.getId() == R.id.action_cancel) {
|
||||||
if (mIsScanning) {
|
if (scanning) {
|
||||||
dialog.cancel();
|
dialog.cancel();
|
||||||
} else {
|
} else {
|
||||||
startScan();
|
startScan();
|
||||||
@@ -187,10 +189,10 @@ public class ScannerFragment extends DialogFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCancel(DialogInterface dialog) {
|
public void onCancel(@NonNull DialogInterface dialog) {
|
||||||
super.onCancel(dialog);
|
super.onCancel(dialog);
|
||||||
|
|
||||||
mListener.onDialogCanceled();
|
listener.onDialogCanceled();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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.
|
// We have been granted the Manifest.permission.ACCESS_FINE_LOCATION permission. Now we may proceed with scanning.
|
||||||
startScan();
|
startScan();
|
||||||
} else {
|
} else {
|
||||||
mPermissionRationale.setVisibility(View.VISIBLE);
|
permissionRationale.setVisibility(View.VISIBLE);
|
||||||
Toast.makeText(getActivity(), R.string.no_required_permission, Toast.LENGTH_SHORT).show();
|
Toast.makeText(getActivity(), R.string.no_required_permission, Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
break;
|
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.
|
* is activated This will perform regular scan for custom BLE Service UUID and then filter out.
|
||||||
* using class ScannerServiceParser
|
* using class ScannerServiceParser
|
||||||
*/
|
*/
|
||||||
@@ -220,8 +222,8 @@ public class ScannerFragment extends DialogFragment {
|
|||||||
// On API older than Marshmallow the following code does nothing.
|
// On API older than Marshmallow the following code does nothing.
|
||||||
if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
|
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
|
// 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) {
|
if (ActivityCompat.shouldShowRequestPermissionRationale(requireActivity(), Manifest.permission.ACCESS_FINE_LOCATION) && permissionRationale.getVisibility() == View.GONE) {
|
||||||
mPermissionRationale.setVisibility(View.VISIBLE);
|
permissionRationale.setVisibility(View.VISIBLE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,23 +232,23 @@ public class ScannerFragment extends DialogFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Hide the rationale message, we don't need it anymore.
|
// Hide the rationale message, we don't need it anymore.
|
||||||
if (mPermissionRationale != null)
|
if (permissionRationale != null)
|
||||||
mPermissionRationale.setVisibility(View.GONE);
|
permissionRationale.setVisibility(View.GONE);
|
||||||
|
|
||||||
mAdapter.clearDevices();
|
adapter.clearDevices();
|
||||||
mScanButton.setText(R.string.scanner_action_cancel);
|
scanButton.setText(R.string.scanner_action_cancel);
|
||||||
|
|
||||||
final BluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();
|
final BluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();
|
||||||
final ScanSettings settings = new ScanSettings.Builder()
|
final ScanSettings settings = new ScanSettings.Builder()
|
||||||
.setLegacy(false)
|
.setLegacy(false)
|
||||||
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).setReportDelay(1000).setUseHardwareBatchingIfSupported(false).build();
|
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).setReportDelay(1000).setUseHardwareBatchingIfSupported(false).build();
|
||||||
final List<ScanFilter> filters = new ArrayList<>();
|
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);
|
scanner.startScan(filters, settings, scanCallback);
|
||||||
|
|
||||||
mIsScanning = true;
|
scanning = true;
|
||||||
mHandler.postDelayed(() -> {
|
handler.postDelayed(() -> {
|
||||||
if (mIsScanning) {
|
if (scanning) {
|
||||||
stopScan();
|
stopScan();
|
||||||
}
|
}
|
||||||
}, SCAN_DURATION);
|
}, SCAN_DURATION);
|
||||||
@@ -256,25 +258,25 @@ public class ScannerFragment extends DialogFragment {
|
|||||||
* Stop scan if user tap Cancel button
|
* Stop scan if user tap Cancel button
|
||||||
*/
|
*/
|
||||||
private void stopScan() {
|
private void stopScan() {
|
||||||
if (mIsScanning) {
|
if (scanning) {
|
||||||
mScanButton.setText(R.string.scanner_action_scan);
|
scanButton.setText(R.string.scanner_action_scan);
|
||||||
|
|
||||||
final BluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();
|
final BluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();
|
||||||
scanner.stopScan(scanCallback);
|
scanner.stopScan(scanCallback);
|
||||||
|
|
||||||
mIsScanning = false;
|
scanning = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ScanCallback scanCallback = new ScanCallback() {
|
private ScanCallback scanCallback = new ScanCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onScanResult(final int callbackType, final ScanResult result) {
|
public void onScanResult(final int callbackType, @NonNull final ScanResult result) {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBatchScanResults(final List<ScanResult> results) {
|
public void onBatchScanResults(@NonNull final List<ScanResult> results) {
|
||||||
mAdapter.update(results);
|
adapter.update(results);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -284,7 +286,7 @@ public class ScannerFragment extends DialogFragment {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private void addBoundDevices() {
|
private void addBoundDevices() {
|
||||||
final Set<BluetoothDevice> devices = mBluetoothAdapter.getBondedDevices();
|
final Set<BluetoothDevice> devices = bluetoothAdapter.getBondedDevices();
|
||||||
mAdapter.addBondedDevices(devices);
|
adapter.addBondedDevices(devices);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,8 +47,8 @@ public class TemplateActivity extends BleProfileServiceReadyActivity<TemplateSer
|
|||||||
private final String TAG = "TemplateActivity";
|
private final String TAG = "TemplateActivity";
|
||||||
|
|
||||||
// TODO change view references to match your need
|
// TODO change view references to match your need
|
||||||
private TextView mValueView;
|
private TextView valueView;
|
||||||
private TextView mBatteryLevelView;
|
private TextView batteryLevelView;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreateView(final Bundle savedInstanceState) {
|
protected void onCreateView(final Bundle savedInstanceState) {
|
||||||
@@ -59,8 +59,8 @@ public class TemplateActivity extends BleProfileServiceReadyActivity<TemplateSer
|
|||||||
|
|
||||||
private void setGUI() {
|
private void setGUI() {
|
||||||
// TODO assign your views to fields
|
// TODO assign your views to fields
|
||||||
mValueView = findViewById(R.id.value);
|
valueView = findViewById(R.id.value);
|
||||||
mBatteryLevelView = findViewById(R.id.battery);
|
batteryLevelView = findViewById(R.id.battery);
|
||||||
|
|
||||||
findViewById(R.id.action_set_name).setOnClickListener(v -> {
|
findViewById(R.id.action_set_name).setOnClickListener(v -> {
|
||||||
if (isDeviceConnected()) {
|
if (isDeviceConnected()) {
|
||||||
@@ -71,20 +71,20 @@ public class TemplateActivity extends BleProfileServiceReadyActivity<TemplateSer
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onInitialize(final Bundle savedInstanceState) {
|
protected void onInitialize(final Bundle savedInstanceState) {
|
||||||
LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, makeIntentFilter());
|
LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, makeIntentFilter());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver);
|
LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setDefaultUI() {
|
protected void setDefaultUI() {
|
||||||
// TODO clear your UI
|
// TODO clear your UI
|
||||||
mValueView.setText(R.string.not_available_value);
|
valueView.setText(R.string.not_available_value);
|
||||||
mBatteryLevelView.setText(R.string.not_available);
|
batteryLevelView.setText(R.string.not_available);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -142,29 +142,29 @@ public class TemplateActivity extends BleProfileServiceReadyActivity<TemplateSer
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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
|
// this may notify user or show some views
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceDisconnected(final BluetoothDevice device) {
|
public void onDeviceDisconnected(@NonNull final BluetoothDevice device) {
|
||||||
super.onDeviceDisconnected(device);
|
super.onDeviceDisconnected(device);
|
||||||
mBatteryLevelView.setText(R.string.not_available);
|
batteryLevelView.setText(R.string.not_available);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handling updates from the device
|
// Handling updates from the device
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private void setValueOnView(@NonNull final BluetoothDevice device, final int value) {
|
private void setValueOnView(@NonNull final BluetoothDevice device, final int value) {
|
||||||
// TODO assign the value to a view
|
// TODO assign the value to a view
|
||||||
mValueView.setText(String.valueOf(value));
|
valueView.setText(String.valueOf(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int value) {
|
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
|
@Override
|
||||||
public void onReceive(final Context context, final Intent intent) {
|
public void onReceive(final Context context, final Intent intent) {
|
||||||
final String action = intent.getAction();
|
final String action = intent.getAction();
|
||||||
|
|||||||
@@ -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
|
private static final UUID WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00002A00-0000-1000-8000-00805f9b34fb"); // Device Name
|
||||||
|
|
||||||
// TODO Add more services and characteristics references.
|
// TODO Add more services and characteristics references.
|
||||||
private BluetoothGattCharacteristic mRequiredCharacteristic, mDeviceNameCharacteristic, mOptionalCharacteristic;
|
private BluetoothGattCharacteristic requiredCharacteristic, deviceNameCharacteristic, optionalCharacteristic;
|
||||||
|
|
||||||
public TemplateManager(final Context context) {
|
public TemplateManager(final Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
@@ -78,14 +78,14 @@ public class TemplateManager extends BatteryManager<TemplateManagerCallbacks> {
|
|||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
protected BatteryManagerGattCallback getGattCallback() {
|
protected BatteryManagerGattCallback getGattCallback() {
|
||||||
return mGattCallback;
|
return gattCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BluetoothGatt callbacks for connection/disconnection, service discovery,
|
* BluetoothGatt callbacks for connection/disconnection, service discovery,
|
||||||
* receiving indication, etc.
|
* receiving indication, etc.
|
||||||
*/
|
*/
|
||||||
private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() {
|
private final BatteryManagerGattCallback gattCallback = new BatteryManagerGattCallback() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initialize() {
|
protected void initialize() {
|
||||||
@@ -111,7 +111,7 @@ public class TemplateManager extends BatteryManager<TemplateManagerCallbacks> {
|
|||||||
.enqueue();
|
.enqueue();
|
||||||
|
|
||||||
// Set notification callback
|
// Set notification callback
|
||||||
setNotificationCallback(mRequiredCharacteristic)
|
setNotificationCallback(requiredCharacteristic)
|
||||||
// This callback will be called each time the notification is received
|
// This callback will be called each time the notification is received
|
||||||
.with(new TemplateDataCallback() {
|
.with(new TemplateDataCallback() {
|
||||||
@Override
|
@Override
|
||||||
@@ -123,7 +123,7 @@ public class TemplateManager extends BatteryManager<TemplateManagerCallbacks> {
|
|||||||
@Override
|
@Override
|
||||||
public void onSampleValueReceived(@NonNull final BluetoothDevice device, final int value) {
|
public void onSampleValueReceived(@NonNull final BluetoothDevice device, final int value) {
|
||||||
// Let's lass received data to the service
|
// Let's lass received data to the service
|
||||||
mCallbacks.onSampleValueReceived(device, value);
|
callbacks.onSampleValueReceived(device, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -133,7 +133,7 @@ public class TemplateManager extends BatteryManager<TemplateManagerCallbacks> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Enable notifications
|
// Enable notifications
|
||||||
enableNotifications(mRequiredCharacteristic)
|
enableNotifications(requiredCharacteristic)
|
||||||
// Method called after the data were sent (data will contain 0x0100 in this case)
|
// Method called after the data were sent (data will contain 0x0100 in this case)
|
||||||
.with((device, data) -> log(Log.DEBUG, "Data sent: " + data))
|
.with((device, data) -> log(Log.DEBUG, "Data sent: " + data))
|
||||||
// Method called when the request finished successfully. This will be called after .with(..) callback
|
// 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).
|
// It should return true if all has been discovered (that is that device is supported).
|
||||||
final BluetoothGattService service = gatt.getService(SERVICE_UUID);
|
final BluetoothGattService service = gatt.getService(SERVICE_UUID);
|
||||||
if (service != null) {
|
if (service != null) {
|
||||||
mRequiredCharacteristic = service.getCharacteristic(MEASUREMENT_CHARACTERISTIC_UUID);
|
requiredCharacteristic = service.getCharacteristic(MEASUREMENT_CHARACTERISTIC_UUID);
|
||||||
}
|
}
|
||||||
final BluetoothGattService otherService = gatt.getService(OTHER_SERVICE_UUID);
|
final BluetoothGattService otherService = gatt.getService(OTHER_SERVICE_UUID);
|
||||||
if (otherService != null) {
|
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
|
@Override
|
||||||
@@ -166,9 +166,9 @@ public class TemplateManager extends BatteryManager<TemplateManagerCallbacks> {
|
|||||||
// TODO If there are some optional characteristics, initialize them there.
|
// TODO If there are some optional characteristics, initialize them there.
|
||||||
final BluetoothGattService service = gatt.getService(SERVICE_UUID);
|
final BluetoothGattService service = gatt.getService(SERVICE_UUID);
|
||||||
if (service != null) {
|
if (service != null) {
|
||||||
mOptionalCharacteristic = service.getCharacteristic(READABLE_CHARACTERISTIC_UUID);
|
optionalCharacteristic = service.getCharacteristic(READABLE_CHARACTERISTIC_UUID);
|
||||||
}
|
}
|
||||||
return mOptionalCharacteristic != null;
|
return optionalCharacteristic != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -177,9 +177,9 @@ public class TemplateManager extends BatteryManager<TemplateManagerCallbacks> {
|
|||||||
super.onDeviceDisconnected();
|
super.onDeviceDisconnected();
|
||||||
|
|
||||||
// TODO Release references to your characteristics.
|
// TODO Release references to your characteristics.
|
||||||
mRequiredCharacteristic = null;
|
requiredCharacteristic = null;
|
||||||
mDeviceNameCharacteristic = null;
|
deviceNameCharacteristic = null;
|
||||||
mOptionalCharacteristic = null;
|
optionalCharacteristic = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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
|
// Device is ready, let's read something here. Usually there is nothing else to be done
|
||||||
// here, as all had been done during initialization.
|
// here, as all had been done during initialization.
|
||||||
readCharacteristic(mOptionalCharacteristic)
|
readCharacteristic(optionalCharacteristic)
|
||||||
.with((device, data) -> {
|
.with((device, data) -> {
|
||||||
// Characteristic value has been read
|
// Characteristic value has been read
|
||||||
// Let's do some magic with it.
|
// Let's do some magic with it.
|
||||||
@@ -217,7 +217,7 @@ public class TemplateManager extends BatteryManager<TemplateManagerCallbacks> {
|
|||||||
void performAction(final String parameter) {
|
void performAction(final String parameter) {
|
||||||
log(Log.VERBOSE, "Changing device name to \"" + parameter + "\"");
|
log(Log.VERBOSE, "Changing device name to \"" + parameter + "\"");
|
||||||
// Write some data to the characteristic.
|
// 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.
|
// If data are longer than MTU-3, they will be chunked into multiple packets.
|
||||||
// Check out other split options, with .split(...).
|
// Check out other split options, with .split(...).
|
||||||
.split()
|
.split()
|
||||||
|
|||||||
@@ -55,9 +55,9 @@ public class TemplateService extends BleProfileService implements TemplateManage
|
|||||||
private final static int OPEN_ACTIVITY_REQ = 0;
|
private final static int OPEN_ACTIVITY_REQ = 0;
|
||||||
private final static int DISCONNECT_REQ = 1;
|
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.
|
* 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.
|
* @param parameter some parameter.
|
||||||
*/
|
*/
|
||||||
public void performAction(final String parameter) {
|
void performAction(final String parameter) {
|
||||||
mManager.performAction(parameter);
|
manager.performAction(parameter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected LocalBinder getBinder() {
|
protected LocalBinder getBinder() {
|
||||||
return mBinder;
|
return binder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected LoggableBleManager<TemplateManagerCallbacks> initializeManager() {
|
protected LoggableBleManager<TemplateManagerCallbacks> initializeManager() {
|
||||||
return mManager = new TemplateManager(this);
|
return manager = new TemplateManager(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -91,14 +91,14 @@ public class TemplateService extends BleProfileService implements TemplateManage
|
|||||||
|
|
||||||
final IntentFilter filter = new IntentFilter();
|
final IntentFilter filter = new IntentFilter();
|
||||||
filter.addAction(ACTION_DISCONNECT);
|
filter.addAction(ACTION_DISCONNECT);
|
||||||
registerReceiver(mDisconnectActionBroadcastReceiver, filter);
|
registerReceiver(disconnectActionBroadcastReceiver, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
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
|
// when user has disconnected from the sensor, we have to cancel the notification that we've created some milliseconds before using unbindService
|
||||||
stopForegroundService();
|
stopForegroundService();
|
||||||
unregisterReceiver(mDisconnectActionBroadcastReceiver);
|
unregisterReceiver(disconnectActionBroadcastReceiver);
|
||||||
|
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
}
|
}
|
||||||
@@ -120,7 +120,7 @@ public class TemplateService extends BleProfileService implements TemplateManage
|
|||||||
broadcast.putExtra(EXTRA_DATA, value);
|
broadcast.putExtra(EXTRA_DATA, value);
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||||
|
|
||||||
if (!mBound) {
|
if (!bound) {
|
||||||
// Here we may update the notification to display the current value.
|
// Here we may update the notification to display the current value.
|
||||||
// TODO modify the notification here
|
// TODO modify the notification here
|
||||||
}
|
}
|
||||||
@@ -166,6 +166,7 @@ public class TemplateService extends BleProfileService implements TemplateManage
|
|||||||
* f.e. <code><string name="name">%s is connected</string></code>
|
* f.e. <code><string name="name">%s is connected</string></code>
|
||||||
* @param defaults signals that will be used to notify the user
|
* @param defaults signals that will be used to notify the user
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("SameParameterValue")
|
||||||
private Notification createNotification(final int messageResId, final int defaults) {
|
private Notification createNotification(final int messageResId, final int defaults) {
|
||||||
final Intent parentIntent = new Intent(this, FeaturesActivity.class);
|
final Intent parentIntent = new Intent(this, FeaturesActivity.class);
|
||||||
parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
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.
|
* 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
|
@Override
|
||||||
public void onReceive(final Context context, final Intent intent) {
|
public void onReceive(final Context context, final Intent intent) {
|
||||||
Logger.i(getLogSession(), "[Notification] Disconnect action pressed");
|
Logger.i(getLogSession(), "[Notification] Disconnect action pressed");
|
||||||
|
|||||||
@@ -115,28 +115,28 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
|
|||||||
private final static int SELECT_FILE_REQ = 2678; // random
|
private final static int SELECT_FILE_REQ = 2678; // random
|
||||||
private final static int PERMISSION_REQ = 24; // random, 8-bit
|
private final static int PERMISSION_REQ = 24; // random, 8-bit
|
||||||
|
|
||||||
UARTConfigurationSynchronizer mWearableSynchronizer;
|
UARTConfigurationSynchronizer wearableSynchronizer;
|
||||||
|
|
||||||
/** The current configuration. */
|
/** The current configuration. */
|
||||||
private UartConfiguration mConfiguration;
|
private UartConfiguration configuration;
|
||||||
private DatabaseHelper mDatabaseHelper;
|
private DatabaseHelper databaseHelper;
|
||||||
private SharedPreferences mPreferences;
|
private SharedPreferences preferences;
|
||||||
private UARTConfigurationsAdapter mConfigurationsAdapter;
|
private UARTConfigurationsAdapter configurationsAdapter;
|
||||||
private ClosableSpinner mConfigurationSpinner;
|
private ClosableSpinner configurationSpinner;
|
||||||
private SlidingPaneLayout mSlider;
|
private SlidingPaneLayout slider;
|
||||||
private View mContainer;
|
private View container;
|
||||||
private UARTService.UARTBinder mServiceBinder;
|
private UARTService.UARTBinder serviceBinder;
|
||||||
private ConfigurationListener mConfigurationListener;
|
private ConfigurationListener configurationListener;
|
||||||
private boolean mEditMode;
|
private boolean editMode;
|
||||||
|
|
||||||
public interface ConfigurationListener {
|
public interface ConfigurationListener {
|
||||||
void onConfigurationModified();
|
void onConfigurationModified();
|
||||||
void onConfigurationChanged(final UartConfiguration configuration);
|
void onConfigurationChanged(@NonNull final UartConfiguration configuration);
|
||||||
void setEditMode(final boolean editMode);
|
void setEditMode(final boolean editMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setConfigurationListener(final ConfigurationListener listener) {
|
public void setConfigurationListener(final ConfigurationListener listener) {
|
||||||
mConfigurationListener = listener;
|
configurationListener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -161,23 +161,23 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onServiceBound(final UARTService.UARTBinder binder) {
|
protected void onServiceBound(final UARTService.UARTBinder binder) {
|
||||||
mServiceBinder = binder;
|
serviceBinder = binder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onServiceUnbound() {
|
protected void onServiceUnbound() {
|
||||||
mServiceBinder = null;
|
serviceBinder = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onInitialize(final Bundle savedInstanceState) {
|
protected void onInitialize(final Bundle savedInstanceState) {
|
||||||
mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
|
preferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
mDatabaseHelper = new DatabaseHelper(this);
|
databaseHelper = new DatabaseHelper(this);
|
||||||
ensureFirstConfiguration(mDatabaseHelper);
|
ensureFirstConfiguration(databaseHelper);
|
||||||
mConfigurationsAdapter = new UARTConfigurationsAdapter(this, this, mDatabaseHelper.getConfigurationsNames());
|
configurationsAdapter = new UARTConfigurationsAdapter(this, this, databaseHelper.getConfigurationsNames());
|
||||||
|
|
||||||
// Initialize Wearable synchronizer
|
// 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
|
@Override
|
||||||
public void onConnected(final Bundle bundle) {
|
public void onConnected(final Bundle bundle) {
|
||||||
// Ensure the Wearable API was connected
|
// Ensure the Wearable API was connected
|
||||||
if (!mWearableSynchronizer.hasConnectedApi())
|
if (!wearableSynchronizer.hasConnectedApi())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!mPreferences.getBoolean(PREFS_WEAR_SYNCED, false)) {
|
if (!preferences.getBoolean(PREFS_WEAR_SYNCED, false)) {
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
final Cursor cursor = mDatabaseHelper.getConfigurations();
|
final Cursor cursor = databaseHelper.getConfigurations();
|
||||||
try {
|
try {
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
final long id = cursor.getLong(0 /* _ID */);
|
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 Format format = new Format(new HyphenStyle());
|
||||||
final Serializer serializer = new Persister(format);
|
final Serializer serializer = new Persister(format);
|
||||||
final UartConfiguration configuration = serializer.read(UartConfiguration.class, xml);
|
final UartConfiguration configuration = serializer.read(UartConfiguration.class, xml);
|
||||||
mWearableSynchronizer.onConfigurationAddedOrEdited(id, configuration).await();
|
wearableSynchronizer.onConfigurationAddedOrEdited(id, configuration).await();
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
Log.w(TAG, "Deserializing configuration with id " + id + " failed", 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 {
|
} finally {
|
||||||
cursor.close();
|
cursor.close();
|
||||||
}
|
}
|
||||||
@@ -225,16 +225,16 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
|
|||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
mWearableSynchronizer.close();
|
wearableSynchronizer.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreateView(final Bundle savedInstanceState) {
|
protected void onCreateView(final Bundle savedInstanceState) {
|
||||||
setContentView(R.layout.activity_feature_uart);
|
setContentView(R.layout.activity_feature_uart);
|
||||||
|
|
||||||
mContainer = findViewById(R.id.container);
|
container = findViewById(R.id.container);
|
||||||
// Setup the sliding pane if it exists
|
// 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) {
|
if (slidingPane != null) {
|
||||||
slidingPane.setSliderFadeColor(Color.TRANSPARENT);
|
slidingPane.setSliderFadeColor(Color.TRANSPARENT);
|
||||||
slidingPane.setShadowResourceLeft(R.drawable.shadow_r);
|
slidingPane.setShadowResourceLeft(R.drawable.shadow_r);
|
||||||
@@ -253,34 +253,34 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
|
|||||||
protected void onViewCreated(final Bundle savedInstanceState) {
|
protected void onViewCreated(final Bundle savedInstanceState) {
|
||||||
getSupportActionBar().setDisplayShowTitleEnabled(false);
|
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.setOnItemSelectedListener(this);
|
||||||
configurationSpinner.setAdapter(mConfigurationsAdapter);
|
configurationSpinner.setAdapter(configurationsAdapter);
|
||||||
configurationSpinner.setSelection(mConfigurationsAdapter.getItemPosition(mPreferences.getLong(PREFS_CONFIGURATION, 0)));
|
configurationSpinner.setSelection(configurationsAdapter.getItemPosition(preferences.getLong(PREFS_CONFIGURATION, 0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onRestoreInstanceState(final @NonNull Bundle savedInstanceState) {
|
protected void onRestoreInstanceState(final @NonNull Bundle savedInstanceState) {
|
||||||
super.onRestoreInstanceState(savedInstanceState);
|
super.onRestoreInstanceState(savedInstanceState);
|
||||||
|
|
||||||
mEditMode = savedInstanceState.getBoolean(SIS_EDIT_MODE);
|
editMode = savedInstanceState.getBoolean(SIS_EDIT_MODE);
|
||||||
setEditMode(mEditMode, false);
|
setEditMode(editMode, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSaveInstanceState(final Bundle outState) {
|
public void onSaveInstanceState(@NonNull final Bundle outState) {
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
|
|
||||||
outState.putBoolean(SIS_EDIT_MODE, mEditMode);
|
outState.putBoolean(SIS_EDIT_MODE, editMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) {
|
public void onServicesDiscovered(@NonNull final BluetoothDevice device, final boolean optionalServicesFound) {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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
|
// The super method starts the service
|
||||||
super.onDeviceSelected(device, name);
|
super.onDeviceSelected(device, name);
|
||||||
|
|
||||||
@@ -306,8 +306,8 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void send(final String text) {
|
public void send(final String text) {
|
||||||
if (mServiceBinder != null)
|
if (serviceBinder != null)
|
||||||
mServiceBinder.send(text);
|
serviceBinder.send(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setEditMode(final boolean editMode) {
|
public void setEditMode(final boolean editMode) {
|
||||||
@@ -317,11 +317,11 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBackPressed() {
|
public void onBackPressed() {
|
||||||
if (mSlider != null && mSlider.isOpen()) {
|
if (slider != null && slider.isOpen()) {
|
||||||
mSlider.closePane();
|
slider.closePane();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (mEditMode) {
|
if (editMode) {
|
||||||
setEditMode(false);
|
setEditMode(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -331,31 +331,31 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
|
|||||||
@Override
|
@Override
|
||||||
public boolean onCreateOptionsMenu(final Menu menu) {
|
public boolean onCreateOptionsMenu(final Menu menu) {
|
||||||
getMenuInflater().inflate(R.menu.uart_menu_configurations, 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);
|
menu.findItem(R.id.action_remove).setVisible(configurationsCount > 1);
|
||||||
return super.onCreateOptionsMenu(menu);
|
return super.onCreateOptionsMenu(menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean onOptionsItemSelected(int itemId) {
|
protected boolean onOptionsItemSelected(int itemId) {
|
||||||
final String name = mConfiguration.getName();
|
final String name = configuration.getName();
|
||||||
switch (itemId) {
|
switch (itemId) {
|
||||||
case R.id.action_configure:
|
case R.id.action_configure:
|
||||||
setEditMode(!mEditMode);
|
setEditMode(!editMode);
|
||||||
return true;
|
return true;
|
||||||
case R.id.action_show_log:
|
case R.id.action_show_log:
|
||||||
mSlider.openPane();
|
slider.openPane();
|
||||||
return true;
|
return true;
|
||||||
case R.id.action_share: {
|
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);
|
final Intent intent = new Intent(Intent.ACTION_SEND);
|
||||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
intent.setType("text/xml");
|
intent.setType("text/xml");
|
||||||
intent.putExtra(Intent.EXTRA_TEXT, xml);
|
intent.putExtra(Intent.EXTRA_TEXT, xml);
|
||||||
intent.putExtra(Intent.EXTRA_SUBJECT, mConfiguration.getName());
|
intent.putExtra(Intent.EXTRA_SUBJECT, configuration.getName());
|
||||||
try {
|
try {
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
} catch (final ActivityNotFoundException e) {
|
} catch (final ActivityNotFoundException e) {
|
||||||
@@ -384,17 +384,17 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case R.id.action_remove: {
|
case R.id.action_remove: {
|
||||||
mDatabaseHelper.removeDeletedServerConfigurations(); // just to be sure nothing has left
|
databaseHelper.removeDeletedServerConfigurations(); // just to be sure nothing has left
|
||||||
final UartConfiguration removedConfiguration = mConfiguration;
|
final UartConfiguration removedConfiguration = configuration;
|
||||||
final long id = mDatabaseHelper.deleteConfiguration(name);
|
final long id = databaseHelper.deleteConfiguration(name);
|
||||||
if (id >= 0)
|
if (id >= 0)
|
||||||
mWearableSynchronizer.onConfigurationDeleted(id);
|
wearableSynchronizer.onConfigurationDeleted(id);
|
||||||
refreshConfigurations();
|
refreshConfigurations();
|
||||||
|
|
||||||
final Snackbar snackbar = Snackbar.make(mContainer, R.string.uart_configuration_deleted, Snackbar.LENGTH_INDEFINITE).setAction(R.string.uart_action_undo, v -> {
|
final Snackbar snackbar = Snackbar.make(container, R.string.uart_configuration_deleted, Snackbar.LENGTH_INDEFINITE).setAction(R.string.uart_action_undo, v -> {
|
||||||
final long id1 = mDatabaseHelper.restoreDeletedServerConfiguration(name);
|
final long id1 = databaseHelper.restoreDeletedServerConfiguration(name);
|
||||||
if (id1 >= 0)
|
if (id1 >= 0)
|
||||||
mWearableSynchronizer.onConfigurationAddedOrEdited(id1, removedConfiguration);
|
wearableSynchronizer.onConfigurationAddedOrEdited(id1, removedConfiguration);
|
||||||
refreshConfigurations();
|
refreshConfigurations();
|
||||||
});
|
});
|
||||||
snackbar.setDuration(5000); // This is not an error
|
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) {
|
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.
|
if (position > 0) { // FIXME this is called twice after rotation.
|
||||||
try {
|
try {
|
||||||
final String xml = mDatabaseHelper.getConfiguration(id);
|
final String xml = databaseHelper.getConfiguration(id);
|
||||||
final Format format = new Format(new HyphenStyle());
|
final Format format = new Format(new HyphenStyle());
|
||||||
final Serializer serializer = new Persister(format);
|
final Serializer serializer = new Persister(format);
|
||||||
mConfiguration = serializer.read(UartConfiguration.class, xml);
|
configuration = serializer.read(UartConfiguration.class, xml);
|
||||||
mConfigurationListener.onConfigurationChanged(mConfiguration);
|
configurationListener.onConfigurationChanged(configuration);
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
Log.e(TAG, "Selecting configuration failed", e);
|
Log.e(TAG, "Selecting configuration failed", e);
|
||||||
|
|
||||||
@@ -441,11 +441,11 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
|
|||||||
else
|
else
|
||||||
message = "Unknown error";
|
message = "Unknown error";
|
||||||
final String msg = message;
|
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;
|
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
|
@Override
|
||||||
public void onNewConfigurationClick() {
|
public void onNewConfigurationClick() {
|
||||||
// No item has been selected. We must close the spinner manually.
|
// No item has been selected. We must close the spinner manually.
|
||||||
mConfigurationSpinner.close();
|
configurationSpinner.close();
|
||||||
|
|
||||||
// Open the dialog
|
// Open the dialog
|
||||||
final DialogFragment fragment = UARTNewConfigurationDialogFragment.getInstance(null, false);
|
final DialogFragment fragment = UARTNewConfigurationDialogFragment.getInstance(null, false);
|
||||||
@@ -469,7 +469,7 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
|
|||||||
@Override
|
@Override
|
||||||
public void onImportClick() {
|
public void onImportClick() {
|
||||||
// No item has been selected. We must close the spinner manually.
|
// No item has been selected. We must close the spinner manually.
|
||||||
mConfigurationSpinner.close();
|
configurationSpinner.close();
|
||||||
|
|
||||||
final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||||
intent.setType("text/xml");
|
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) {
|
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.setCommand(message);
|
||||||
command.setActive(active);
|
command.setActive(active);
|
||||||
command.setEol(eol);
|
command.setEol(eol);
|
||||||
command.setIconIndex(iconIndex);
|
command.setIconIndex(iconIndex);
|
||||||
mConfigurationListener.onConfigurationModified();
|
configurationListener.onConfigurationModified();
|
||||||
saveConfiguration();
|
saveConfiguration();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNewConfiguration(final String name, final boolean duplicate) {
|
public void onNewConfiguration(final String name, final boolean duplicate) {
|
||||||
final boolean exists = mDatabaseHelper.configurationExists(name);
|
final boolean exists = databaseHelper.configurationExists(name);
|
||||||
if (exists) {
|
if (exists) {
|
||||||
Toast.makeText(this, R.string.uart_configuration_name_already_taken, Toast.LENGTH_LONG).show();
|
Toast.makeText(this, R.string.uart_configuration_name_already_taken, Toast.LENGTH_LONG).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
UartConfiguration configuration = mConfiguration;
|
UartConfiguration configuration = this.configuration;
|
||||||
if (!duplicate)
|
if (!duplicate)
|
||||||
configuration = new UartConfiguration();
|
configuration = new UartConfiguration();
|
||||||
configuration.setName(name);
|
configuration.setName(name);
|
||||||
@@ -573,10 +573,10 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
|
|||||||
serializer.write(configuration, writer);
|
serializer.write(configuration, writer);
|
||||||
final String xml = writer.toString();
|
final String xml = writer.toString();
|
||||||
|
|
||||||
final long id = mDatabaseHelper.addConfiguration(name, xml);
|
final long id = databaseHelper.addConfiguration(name, xml);
|
||||||
mWearableSynchronizer.onConfigurationAddedOrEdited(id, configuration);
|
wearableSynchronizer.onConfigurationAddedOrEdited(id, configuration);
|
||||||
refreshConfigurations();
|
refreshConfigurations();
|
||||||
selectConfiguration(mConfigurationsAdapter.getItemPosition(id));
|
selectConfiguration(configurationsAdapter.getItemPosition(id));
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
Log.e(TAG, "Error while creating a new configuration", e);
|
Log.e(TAG, "Error while creating a new configuration", e);
|
||||||
}
|
}
|
||||||
@@ -584,25 +584,25 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRenameConfiguration(final String newName) {
|
public void onRenameConfiguration(final String newName) {
|
||||||
final boolean exists = mDatabaseHelper.configurationExists(newName);
|
final boolean exists = databaseHelper.configurationExists(newName);
|
||||||
if (exists) {
|
if (exists) {
|
||||||
Toast.makeText(this, R.string.uart_configuration_name_already_taken, Toast.LENGTH_LONG).show();
|
Toast.makeText(this, R.string.uart_configuration_name_already_taken, Toast.LENGTH_LONG).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final String oldName = mConfiguration.getName();
|
final String oldName = configuration.getName();
|
||||||
mConfiguration.setName(newName);
|
configuration.setName(newName);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final Format format = new Format(new HyphenStyle());
|
final Format format = new Format(new HyphenStyle());
|
||||||
final Strategy strategy = new VisitorStrategy(new CommentVisitor());
|
final Strategy strategy = new VisitorStrategy(new CommentVisitor());
|
||||||
final Serializer serializer = new Persister(strategy, format);
|
final Serializer serializer = new Persister(strategy, format);
|
||||||
final StringWriter writer = new StringWriter();
|
final StringWriter writer = new StringWriter();
|
||||||
serializer.write(mConfiguration, writer);
|
serializer.write(configuration, writer);
|
||||||
final String xml = writer.toString();
|
final String xml = writer.toString();
|
||||||
|
|
||||||
mDatabaseHelper.renameConfiguration(oldName, newName, xml);
|
databaseHelper.renameConfiguration(oldName, newName, xml);
|
||||||
mWearableSynchronizer.onConfigurationAddedOrEdited(mPreferences.getLong(PREFS_CONFIGURATION, 0), mConfiguration);
|
wearableSynchronizer.onConfigurationAddedOrEdited(preferences.getLong(PREFS_CONFIGURATION, 0), configuration);
|
||||||
refreshConfigurations();
|
refreshConfigurations();
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
Log.e(TAG, "Error while renaming configuration", e);
|
Log.e(TAG, "Error while renaming configuration", e);
|
||||||
@@ -610,13 +610,13 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void refreshConfigurations() {
|
private void refreshConfigurations() {
|
||||||
mConfigurationsAdapter.swapCursor(mDatabaseHelper.getConfigurationsNames());
|
configurationsAdapter.swapCursor(databaseHelper.getConfigurationsNames());
|
||||||
mConfigurationsAdapter.notifyDataSetChanged();
|
configurationsAdapter.notifyDataSetChanged();
|
||||||
invalidateOptionsMenu();
|
invalidateOptionsMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void selectConfiguration(final int position) {
|
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")
|
@SuppressLint("NewApi")
|
||||||
private void setEditMode(final boolean editMode, final boolean change) {
|
private void setEditMode(final boolean editMode, final boolean change) {
|
||||||
mEditMode = editMode;
|
this.editMode = editMode;
|
||||||
mConfigurationListener.setEditMode(editMode);
|
configurationListener.setEditMode(editMode);
|
||||||
if (!change) {
|
if (!change) {
|
||||||
final ColorDrawable color = new ColorDrawable();
|
final ColorDrawable color = new ColorDrawable();
|
||||||
int darkColor = 0;
|
int darkColor = 0;
|
||||||
@@ -664,8 +664,8 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
|
|||||||
anim.start();
|
anim.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mSlider != null && editMode) {
|
if (slider != null && editMode) {
|
||||||
mSlider.closePane();
|
slider.closePane();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -674,7 +674,7 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
|
|||||||
* Saves the given configuration in the database.
|
* Saves the given configuration in the database.
|
||||||
*/
|
*/
|
||||||
private void saveConfiguration() {
|
private void saveConfiguration() {
|
||||||
final UartConfiguration configuration = mConfiguration;
|
final UartConfiguration configuration = this.configuration;
|
||||||
try {
|
try {
|
||||||
final Format format = new Format(new HyphenStyle());
|
final Format format = new Format(new HyphenStyle());
|
||||||
final Strategy strategy = new VisitorStrategy(new CommentVisitor());
|
final Strategy strategy = new VisitorStrategy(new CommentVisitor());
|
||||||
@@ -683,8 +683,8 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
|
|||||||
serializer.write(configuration, writer);
|
serializer.write(configuration, writer);
|
||||||
final String xml = writer.toString();
|
final String xml = writer.toString();
|
||||||
|
|
||||||
mDatabaseHelper.updateConfiguration(configuration.getName(), xml);
|
databaseHelper.updateConfiguration(configuration.getName(), xml);
|
||||||
mWearableSynchronizer.onConfigurationAddedOrEdited(mPreferences.getLong(PREFS_CONFIGURATION, 0), configuration);
|
wearableSynchronizer.onConfigurationAddedOrEdited(preferences.getLong(PREFS_CONFIGURATION, 0), configuration);
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
Log.e(TAG, "Error while creating a new configuration", 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 UartConfiguration configuration = serializer.read(UartConfiguration.class, xml);
|
||||||
|
|
||||||
final String name = configuration.getName();
|
final String name = configuration.getName();
|
||||||
if (!mDatabaseHelper.configurationExists(name)) {
|
if (!databaseHelper.configurationExists(name)) {
|
||||||
final long id = mDatabaseHelper.addConfiguration(name, xml);
|
final long id = databaseHelper.addConfiguration(name, xml);
|
||||||
mWearableSynchronizer.onConfigurationAddedOrEdited(id, configuration);
|
wearableSynchronizer.onConfigurationAddedOrEdited(id, configuration);
|
||||||
refreshConfigurations();
|
refreshConfigurations();
|
||||||
new Handler().post(() -> selectConfiguration(mConfigurationsAdapter.getItemPosition(id)));
|
new Handler().post(() -> selectConfiguration(configurationsAdapter.getItemPosition(id)));
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(this, R.string.uart_configuration_name_already_taken, Toast.LENGTH_LONG).show();
|
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
|
else
|
||||||
message = "Unknown error";
|
message = "Unknown error";
|
||||||
final String msg = message;
|
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())
|
if (!serverFolder.exists())
|
||||||
serverFolder.mkdir();
|
serverFolder.mkdir();
|
||||||
|
|
||||||
final String fileName = mConfiguration.getName() + ".xml";
|
final String fileName = configuration.getName() + ".xml";
|
||||||
final File file = new File(serverFolder, fileName);
|
final File file = new File(serverFolder, fileName);
|
||||||
try {
|
try {
|
||||||
file.createNewFile();
|
file.createNewFile();
|
||||||
final FileOutputStream fos = new FileOutputStream(file);
|
final FileOutputStream fos = new FileOutputStream(file);
|
||||||
final OutputStreamWriter writer = new OutputStreamWriter(fos);
|
final OutputStreamWriter writer = new OutputStreamWriter(fos);
|
||||||
writer.append(mDatabaseHelper.getConfiguration(mConfigurationSpinner.getSelectedItemId()));
|
writer.append(databaseHelper.getConfiguration(configurationSpinner.getSelectedItemId()));
|
||||||
writer.close();
|
writer.close();
|
||||||
|
|
||||||
// Notify user about the file
|
// 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.
|
* 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.
|
* 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.
|
// 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();
|
final UartConfiguration configuration = new UartConfiguration();
|
||||||
configuration.setName("First configuration");
|
configuration.setName("First configuration");
|
||||||
final Command[] commands = configuration.getCommands();
|
final Command[] commands = configuration.getCommands();
|
||||||
|
|
||||||
for (int i = 0; i < 9; ++i) {
|
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) {
|
if (cmd != null) {
|
||||||
final Command command = new Command();
|
final Command command = new Command();
|
||||||
command.setCommand(cmd);
|
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.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;
|
commands[i] = command;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -795,7 +795,7 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
|
|||||||
serializer.write(configuration, writer);
|
serializer.write(configuration, writer);
|
||||||
final String xml = writer.toString();
|
final String xml = writer.toString();
|
||||||
|
|
||||||
mDatabaseHelper.addConfiguration(configuration.getName(), xml);
|
databaseHelper.addConfiguration(configuration.getName(), xml);
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
Log.e(TAG, "Error while creating default configuration", e);
|
Log.e(TAG, "Error while creating default configuration", e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,36 +28,38 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.BaseAdapter;
|
import android.widget.BaseAdapter;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import no.nordicsemi.android.nrftoolbox.R;
|
import no.nordicsemi.android.nrftoolbox.R;
|
||||||
import no.nordicsemi.android.nrftoolbox.uart.domain.Command;
|
import no.nordicsemi.android.nrftoolbox.uart.domain.Command;
|
||||||
import no.nordicsemi.android.nrftoolbox.uart.domain.UartConfiguration;
|
import no.nordicsemi.android.nrftoolbox.uart.domain.UartConfiguration;
|
||||||
|
|
||||||
public class UARTButtonAdapter extends BaseAdapter {
|
public class UARTButtonAdapter extends BaseAdapter {
|
||||||
private UartConfiguration mConfiguration;
|
private UartConfiguration configuration;
|
||||||
private boolean mEditMode;
|
private boolean editMode;
|
||||||
|
|
||||||
public UARTButtonAdapter(final UartConfiguration configuration) {
|
public UARTButtonAdapter(final UartConfiguration configuration) {
|
||||||
mConfiguration = configuration;
|
this.configuration = configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setEditMode(final boolean editMode) {
|
public void setEditMode(final boolean editMode) {
|
||||||
mEditMode = editMode;
|
this.editMode = editMode;
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setConfiguration(final UartConfiguration configuration) {
|
public void setConfiguration(final UartConfiguration configuration) {
|
||||||
mConfiguration = configuration;
|
this.configuration = configuration;
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getCount() {
|
public int getCount() {
|
||||||
return mConfiguration != null ? mConfiguration.getCommands().length : 0;
|
return configuration != null ? configuration.getCommands().length : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getItem(final int position) {
|
public Object getItem(final int position) {
|
||||||
return mConfiguration.getCommands()[position];
|
return configuration.getCommands()[position];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -76,20 +78,20 @@ public class UARTButtonAdapter extends BaseAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isEnabled(int position) {
|
public boolean isEnabled(final int position) {
|
||||||
final Command command = (Command) getItem(position);
|
final Command command = (Command) getItem(position);
|
||||||
return mEditMode || (command != null && command.isActive());
|
return editMode || (command != null && command.isActive());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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;
|
View view = convertView;
|
||||||
if (view == null) {
|
if (view == null) {
|
||||||
final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
|
final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
|
||||||
view = inflater.inflate(R.layout.feature_uart_button, parent, false);
|
view = inflater.inflate(R.layout.feature_uart_button, parent, false);
|
||||||
}
|
}
|
||||||
view.setEnabled(isEnabled(position));
|
view.setEnabled(isEnabled(position));
|
||||||
view.setActivated(mEditMode);
|
view.setActivated(editMode);
|
||||||
|
|
||||||
// Update image
|
// Update image
|
||||||
final Command command = (Command) getItem(position);
|
final Command command = (Command) getItem(position);
|
||||||
|
|||||||
@@ -30,21 +30,23 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.CursorAdapter;
|
import android.widget.CursorAdapter;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import no.nordicsemi.android.nrftoolbox.R;
|
import no.nordicsemi.android.nrftoolbox.R;
|
||||||
|
|
||||||
public class UARTConfigurationsAdapter extends CursorAdapter {
|
public class UARTConfigurationsAdapter extends CursorAdapter {
|
||||||
final Context mContext;
|
final Context context;
|
||||||
final ActionListener mListener;
|
final ActionListener listener;
|
||||||
|
|
||||||
public interface ActionListener {
|
public interface ActionListener {
|
||||||
void onNewConfigurationClick();
|
void onNewConfigurationClick();
|
||||||
void onImportClick();
|
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);
|
super(context, c, 0);
|
||||||
mContext = context;
|
this.context = context;
|
||||||
mListener = listener;
|
this.listener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -83,7 +85,7 @@ public class UARTConfigurationsAdapter extends CursorAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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) {
|
if (position == 0) {
|
||||||
// This empty view should never be visible. Only positions 1+ are valid. Position 0 is reserved for action buttons.
|
// 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.
|
// It is only created temporally when activity is created.
|
||||||
@@ -93,9 +95,9 @@ public class UARTConfigurationsAdapter extends CursorAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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) {
|
if (position == 0) {
|
||||||
return newToolbarView(mContext, parent);
|
return newToolbarView(context, parent);
|
||||||
}
|
}
|
||||||
if (convertView instanceof ViewGroup)
|
if (convertView instanceof ViewGroup)
|
||||||
return super.getDropDownView(position - 1, null, parent);
|
return super.getDropDownView(position - 1, null, parent);
|
||||||
@@ -104,18 +106,18 @@ public class UARTConfigurationsAdapter extends CursorAdapter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View newView(final Context context, final Cursor cursor, final ViewGroup parent) {
|
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
|
@Override
|
||||||
public View newDropDownView(final Context context, final Cursor cursor, final ViewGroup parent) {
|
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) {
|
public View newToolbarView(final Context context, final ViewGroup parent) {
|
||||||
final View view = LayoutInflater.from(context).inflate(R.layout.feature_uart_dropdown_title, parent, false);
|
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_add).setOnClickListener(v -> listener.onNewConfigurationClick());
|
||||||
view.findViewById(R.id.action_import).setOnClickListener(v -> mListener.onImportClick());
|
view.findViewById(R.id.action_import).setOnClickListener(v -> listener.onImportClick());
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ package no.nordicsemi.android.nrftoolbox.uart;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
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 TAG = "UARTControlFragment";
|
||||||
private final static String SIS_EDIT_MODE = "sis_edit_mode";
|
private final static String SIS_EDIT_MODE = "sis_edit_mode";
|
||||||
|
|
||||||
private UartConfiguration mConfiguration;
|
private UartConfiguration configuration;
|
||||||
private UARTButtonAdapter mAdapter;
|
private UARTButtonAdapter adapter;
|
||||||
private boolean mEditMode;
|
private boolean editMode;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(final Context context) {
|
public void onAttach(@NonNull final Context context) {
|
||||||
super.onAttach(context);
|
super.onAttach(context);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -60,19 +62,19 @@ public class UARTControlFragment extends Fragment implements GridView.OnItemClic
|
|||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
if (savedInstanceState != null) {
|
if (savedInstanceState != null) {
|
||||||
mEditMode = savedInstanceState.getBoolean(SIS_EDIT_MODE);
|
editMode = savedInstanceState.getBoolean(SIS_EDIT_MODE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
((UARTActivity)getActivity()).setConfigurationListener(null);
|
((UARTActivity)requireActivity()).setConfigurationListener(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSaveInstanceState(final Bundle outState) {
|
public void onSaveInstanceState(final Bundle outState) {
|
||||||
outState.putBoolean(SIS_EDIT_MODE, mEditMode);
|
outState.putBoolean(SIS_EDIT_MODE, editMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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 View view = inflater.inflate(R.layout.fragment_feature_uart_control, container, false);
|
||||||
|
|
||||||
final GridView grid = view.findViewById(R.id.grid);
|
final GridView grid = view.findViewById(R.id.grid);
|
||||||
grid.setAdapter(mAdapter = new UARTButtonAdapter(mConfiguration));
|
grid.setAdapter(adapter = new UARTButtonAdapter(configuration));
|
||||||
grid.setOnItemClickListener(this);
|
grid.setOnItemClickListener(this);
|
||||||
mAdapter.setEditMode(mEditMode);
|
adapter.setEditMode(editMode);
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onItemClick(final AdapterView<?> parent, final View view, final int position, final long id) {
|
public void onItemClick(final AdapterView<?> parent, final View view, final int position, final long id) {
|
||||||
if (mEditMode) {
|
if (editMode) {
|
||||||
Command command = mConfiguration.getCommands()[position];
|
Command command = configuration.getCommands()[position];
|
||||||
if (command == null)
|
if (command == null)
|
||||||
mConfiguration.getCommands()[position] = command = new Command();
|
configuration.getCommands()[position] = command = new Command();
|
||||||
final UARTEditDialog dialog = UARTEditDialog.getInstance(position, command);
|
final UARTEditDialog dialog = UARTEditDialog.getInstance(position, command);
|
||||||
dialog.show(getChildFragmentManager(), null);
|
dialog.show(getChildFragmentManager(), null);
|
||||||
} else {
|
} else {
|
||||||
final Command command = (Command)mAdapter.getItem(position);
|
final Command command = (Command)adapter.getItem(position);
|
||||||
final Command.Eol eol = command.getEol();
|
final Command.Eol eol = command.getEol();
|
||||||
String text = command.getCommand();
|
String text = command.getCommand();
|
||||||
if (text == null)
|
if (text == null)
|
||||||
@@ -109,25 +111,25 @@ public class UARTControlFragment extends Fragment implements GridView.OnItemClic
|
|||||||
text = text.replaceAll("\n", "\r");
|
text = text.replaceAll("\n", "\r");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
final UARTInterface uart = (UARTInterface) getActivity();
|
final UARTInterface uart = (UARTInterface) requireActivity();
|
||||||
uart.send(text);
|
uart.send(text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onConfigurationModified() {
|
public void onConfigurationModified() {
|
||||||
mAdapter.notifyDataSetChanged();
|
adapter.notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onConfigurationChanged(final UartConfiguration configuration) {
|
public void onConfigurationChanged(@NonNull final UartConfiguration configuration) {
|
||||||
mConfiguration = configuration;
|
this.configuration = configuration;
|
||||||
mAdapter.setConfiguration(configuration);
|
adapter.setConfiguration(configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setEditMode(final boolean editMode) {
|
public void setEditMode(final boolean editMode) {
|
||||||
mEditMode = editMode;
|
this.editMode = editMode;
|
||||||
mAdapter.setEditMode(mEditMode);
|
adapter.setEditMode(editMode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ package no.nordicsemi.android.nrftoolbox.uart;
|
|||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import androidx.fragment.app.DialogFragment;
|
import androidx.fragment.app.DialogFragment;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import android.view.LayoutInflater;
|
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_COMMAND = "command";
|
||||||
private final static String ARG_EOL = "eol";
|
private final static String ARG_EOL = "eol";
|
||||||
private final static String ARG_ICON_INDEX = "iconIndex";
|
private final static String ARG_ICON_INDEX = "iconIndex";
|
||||||
private int mActiveIcon;
|
private int activeIcon;
|
||||||
|
|
||||||
private EditText mField;
|
private EditText field;
|
||||||
private CheckBox mActiveCheckBox;
|
private CheckBox activeCheckBox;
|
||||||
private RadioGroup mEOLGroup;
|
private RadioGroup eolGroup;
|
||||||
private IconAdapter mIconAdapter;
|
private IconAdapter iconAdapter;
|
||||||
|
|
||||||
public static UARTEditDialog getInstance(final int index, final Command command) {
|
public static UARTEditDialog getInstance(final int index, final Command command) {
|
||||||
final UARTEditDialog fragment = new UARTEditDialog();
|
final UARTEditDialog fragment = new UARTEditDialog();
|
||||||
@@ -73,27 +74,27 @@ public class UARTEditDialog extends DialogFragment implements View.OnClickListen
|
|||||||
final LayoutInflater inflater = LayoutInflater.from(getActivity());
|
final LayoutInflater inflater = LayoutInflater.from(getActivity());
|
||||||
|
|
||||||
// Read button configuration
|
// Read button configuration
|
||||||
final Bundle args = getArguments();
|
final Bundle args = requireArguments();
|
||||||
final int index = args.getInt(ARG_INDEX);
|
final int index = args.getInt(ARG_INDEX);
|
||||||
final String command = args.getString(ARG_COMMAND);
|
final String command = args.getString(ARG_COMMAND);
|
||||||
final int eol = args.getInt(ARG_EOL);
|
final int eol = args.getInt(ARG_EOL);
|
||||||
final int iconIndex = args.getInt(ARG_ICON_INDEX);
|
final int iconIndex = args.getInt(ARG_ICON_INDEX);
|
||||||
final boolean active = true; // change to active by default
|
final boolean active = true; // change to active by default
|
||||||
mActiveIcon = iconIndex;
|
activeIcon = iconIndex;
|
||||||
|
|
||||||
// Create view
|
// Create view
|
||||||
final View view = inflater.inflate(R.layout.feature_uart_dialog_edit, null);
|
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 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) -> {
|
checkBox.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
||||||
field.setEnabled(isChecked);
|
field.setEnabled(isChecked);
|
||||||
grid.setEnabled(isChecked);
|
grid.setEnabled(isChecked);
|
||||||
if (mIconAdapter != null)
|
if (iconAdapter != null)
|
||||||
mIconAdapter.notifyDataSetChanged();
|
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]) {
|
switch (Command.Eol.values()[eol]) {
|
||||||
case CR_LF:
|
case CR_LF:
|
||||||
eolGroup.check(R.id.uart_eol_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);
|
checkBox.setChecked(active);
|
||||||
grid.setOnItemClickListener(this);
|
grid.setOnItemClickListener(this);
|
||||||
grid.setEnabled(active);
|
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.
|
// 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)
|
final AlertDialog dialog = new AlertDialog.Builder(requireContext())
|
||||||
.setNegativeButton(R.string.cancel, null).setView(view).show();
|
.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);
|
final Button okButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
|
||||||
okButton.setOnClickListener(this);
|
okButton.setOnClickListener(this);
|
||||||
return dialog;
|
return dialog;
|
||||||
@@ -124,11 +130,11 @@ public class UARTEditDialog extends DialogFragment implements View.OnClickListen
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(final View v) {
|
public void onClick(final View v) {
|
||||||
final boolean active = mActiveCheckBox.isChecked();
|
final boolean active = activeCheckBox.isChecked();
|
||||||
final String command = mField.getText().toString();
|
final String command = field.getText().toString();
|
||||||
int eol;
|
int eol;
|
||||||
|
|
||||||
switch (mEOLGroup.getCheckedRadioButtonId()) {
|
switch (eolGroup.getCheckedRadioButtonId()) {
|
||||||
case R.id.uart_eol_cr_lf:
|
case R.id.uart_eol_cr_lf:
|
||||||
eol = Command.Eol.CR_LF.index;
|
eol = Command.Eol.CR_LF.index;
|
||||||
break;
|
break;
|
||||||
@@ -142,18 +148,18 @@ public class UARTEditDialog extends DialogFragment implements View.OnClickListen
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Save values
|
// Save values
|
||||||
final Bundle args = getArguments();
|
final Bundle args = requireArguments();
|
||||||
final int index = args.getInt(ARG_INDEX);
|
final int index = args.getInt(ARG_INDEX);
|
||||||
|
|
||||||
dismiss();
|
dismiss();
|
||||||
final UARTActivity parent = (UARTActivity) getActivity();
|
final UARTActivity parent = (UARTActivity) requireActivity();
|
||||||
parent.onCommandChanged(index, command, active, eol, mActiveIcon);
|
parent.onCommandChanged(index, command, active, eol, activeIcon);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onItemClick(final AdapterView<?> parent, final View view, final int position, final long id) {
|
public void onItemClick(final AdapterView<?> parent, final View view, final int position, final long id) {
|
||||||
mActiveIcon = position;
|
activeIcon = position;
|
||||||
mIconAdapter.notifyDataSetChanged();
|
iconAdapter.notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class IconAdapter extends BaseAdapter {
|
private class IconAdapter extends BaseAdapter {
|
||||||
@@ -175,14 +181,15 @@ public class UARTEditDialog extends DialogFragment implements View.OnClickListen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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;
|
View view = convertView;
|
||||||
if (view == null) {
|
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;
|
final ImageView image = (ImageView) view;
|
||||||
image.setImageLevel(position);
|
image.setImageLevel(position);
|
||||||
image.setActivated(position == mActiveIcon && mActiveCheckBox.isChecked());
|
image.setActivated(position == activeIcon && activeCheckBox.isChecked());
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,15 +39,15 @@ import no.nordicsemi.android.log.LogContract.Log.Level;
|
|||||||
import no.nordicsemi.android.nrftoolbox.R;
|
import no.nordicsemi.android.nrftoolbox.R;
|
||||||
|
|
||||||
public class UARTLogAdapter extends CursorAdapter {
|
public class UARTLogAdapter extends CursorAdapter {
|
||||||
private static final SparseIntArray mColors = new SparseIntArray();
|
private static final SparseIntArray colors = new SparseIntArray();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
mColors.put(Level.DEBUG, 0xFF009CDE);
|
colors.put(Level.DEBUG, 0xFF009CDE);
|
||||||
mColors.put(Level.VERBOSE, 0xFFB8B056);
|
colors.put(Level.VERBOSE, 0xFFB8B056);
|
||||||
mColors.put(Level.INFO, Color.BLACK);
|
colors.put(Level.INFO, Color.BLACK);
|
||||||
mColors.put(Level.APPLICATION, 0xFF238C0F);
|
colors.put(Level.APPLICATION, 0xFF238C0F);
|
||||||
mColors.put(Level.WARNING, 0xFFD77926);
|
colors.put(Level.WARNING, 0xFFD77926);
|
||||||
mColors.put(Level.ERROR, Color.RED);
|
colors.put(Level.ERROR, Color.RED);
|
||||||
}
|
}
|
||||||
|
|
||||||
UARTLogAdapter(@NonNull final Context context) {
|
UARTLogAdapter(@NonNull final Context context) {
|
||||||
@@ -74,7 +74,7 @@ public class UARTLogAdapter extends CursorAdapter {
|
|||||||
|
|
||||||
final int level = cursor.getInt(2 /* LEVEL */);
|
final int level = cursor.getInt(2 /* LEVEL */);
|
||||||
holder.data.setText(cursor.getString(3 /* DATA */));
|
holder.data.setText(cursor.getString(3 /* DATA */));
|
||||||
holder.data.setTextColor(mColors.get(level));
|
holder.data.setTextColor(colors.get(level));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -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.
|
* 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.
|
* 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.
|
* The log session created to log events related with the target device.
|
||||||
*/
|
*/
|
||||||
private ILogSession mLogSession;
|
private ILogSession logSession;
|
||||||
|
|
||||||
private EditText mField;
|
private EditText field;
|
||||||
private Button mSendButton;
|
private Button sendButton;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The last list view position.
|
* The last list view position.
|
||||||
*/
|
*/
|
||||||
private int mLogScrollPosition;
|
private int logScrollPosition;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The receiver that listens for {@link BleProfileService#BROADCAST_CONNECTION_STATE} action.
|
* The receiver that listens for {@link BleProfileService#BROADCAST_CONNECTION_STATE} action.
|
||||||
*/
|
*/
|
||||||
private final BroadcastReceiver mCommonBroadcastReceiver = new BroadcastReceiver() {
|
private final BroadcastReceiver commonBroadcastReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(final Context context, final Intent intent) {
|
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.
|
// 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
|
@Override
|
||||||
public void onServiceConnected(final ComponentName name, final IBinder service) {
|
public void onServiceConnected(final ComponentName name, final IBinder service) {
|
||||||
final UARTService.UARTBinder bleService = (UARTService.UARTBinder) service;
|
final UARTService.UARTBinder bleService = (UARTService.UARTBinder) service;
|
||||||
mUARTInterface = bleService;
|
uartInterface = bleService;
|
||||||
mLogSession = bleService.getLogSession();
|
logSession = bleService.getLogSession();
|
||||||
|
|
||||||
// Start the loader
|
// Start the loader
|
||||||
if (mLogSession != null) {
|
if (logSession != null) {
|
||||||
getLoaderManager().restartLoader(LOG_REQUEST_ID, null, UARTLogFragment.this);
|
getLoaderManager().restartLoader(LOG_REQUEST_ID, null, UARTLogFragment.this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,7 +129,7 @@ public class UARTLogFragment extends ListFragment implements LoaderManager.Loade
|
|||||||
@Override
|
@Override
|
||||||
public void onServiceDisconnected(final ComponentName name) {
|
public void onServiceDisconnected(final ComponentName name) {
|
||||||
onDeviceDisconnected();
|
onDeviceDisconnected();
|
||||||
mUARTInterface = null;
|
uartInterface = null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -137,11 +137,11 @@ public class UARTLogFragment extends ListFragment implements LoaderManager.Loade
|
|||||||
public void onCreate(final Bundle savedInstanceState) {
|
public void onCreate(final Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
LocalBroadcastManager.getInstance(requireContext()).registerReceiver(mCommonBroadcastReceiver, makeIntentFilter());
|
LocalBroadcastManager.getInstance(requireContext()).registerReceiver(commonBroadcastReceiver, makeIntentFilter());
|
||||||
|
|
||||||
// Load the last log list view scroll position
|
// Load the last log list view scroll position
|
||||||
if (savedInstanceState != null) {
|
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
|
* 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);
|
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
|
@Override
|
||||||
@@ -162,8 +162,8 @@ public class UARTLogFragment extends ListFragment implements LoaderManager.Loade
|
|||||||
super.onStop();
|
super.onStop();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
requireActivity().unbindService(mServiceConnection);
|
requireActivity().unbindService(serviceConnection);
|
||||||
mUARTInterface = null;
|
uartInterface = null;
|
||||||
} catch (final IllegalArgumentException e) {
|
} catch (final IllegalArgumentException e) {
|
||||||
// do nothing, we were not connected to the sensor
|
// do nothing, we were not connected to the sensor
|
||||||
}
|
}
|
||||||
@@ -181,7 +181,7 @@ public class UARTLogFragment extends ListFragment implements LoaderManager.Loade
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
LocalBroadcastManager.getInstance(requireContext()).unregisterReceiver(mCommonBroadcastReceiver);
|
LocalBroadcastManager.getInstance(requireContext()).unregisterReceiver(commonBroadcastReceiver);
|
||||||
super.onDestroy();
|
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) {
|
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 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) -> {
|
field.setOnEditorActionListener((v, actionId, event) -> {
|
||||||
if (actionId == EditorInfo.IME_ACTION_SEND) {
|
if (actionId == EditorInfo.IME_ACTION_SEND) {
|
||||||
onSendClicked();
|
onSendClicked();
|
||||||
@@ -198,7 +198,7 @@ public class UARTLogFragment extends ListFragment implements LoaderManager.Loade
|
|||||||
return false;
|
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());
|
sendButton.setOnClickListener(v -> onSendClicked());
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
@@ -208,8 +208,8 @@ public class UARTLogFragment extends ListFragment implements LoaderManager.Loade
|
|||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
|
||||||
// Create the log adapter, initially with null cursor
|
// Create the log adapter, initially with null cursor
|
||||||
mLogAdapter = new UARTLogAdapter(requireContext());
|
logAdapter = new UARTLogAdapter(requireContext());
|
||||||
setListAdapter(mLogAdapter);
|
setListAdapter(logAdapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@@ -217,7 +217,7 @@ public class UARTLogFragment extends ListFragment implements LoaderManager.Loade
|
|||||||
public Loader<Cursor> onCreateLoader(final int id, final Bundle args) {
|
public Loader<Cursor> onCreateLoader(final int id, final Bundle args) {
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case LOG_REQUEST_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);
|
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) {
|
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.
|
// 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 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);
|
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) {
|
if (position > LOG_SCROLL_NULL) {
|
||||||
list.setSelectionFromTop(position, 0);
|
list.setSelectionFromTop(position, 0);
|
||||||
@@ -238,21 +238,21 @@ public class UARTLogFragment extends ListFragment implements LoaderManager.Loade
|
|||||||
if (scrolledToBottom)
|
if (scrolledToBottom)
|
||||||
list.setSelection(list.getCount() - 1);
|
list.setSelection(list.getCount() - 1);
|
||||||
}
|
}
|
||||||
mLogScrollPosition = LOG_SCROLL_NULL;
|
logScrollPosition = LOG_SCROLL_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoaderReset(@NonNull final Loader<Cursor> loader) {
|
public void onLoaderReset(@NonNull final Loader<Cursor> loader) {
|
||||||
mLogAdapter.swapCursor(null);
|
logAdapter.swapCursor(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onSendClicked() {
|
private void onSendClicked() {
|
||||||
final String text = mField.getText().toString();
|
final String text = field.getText().toString();
|
||||||
|
|
||||||
mUARTInterface.send(text);
|
uartInterface.send(text);
|
||||||
|
|
||||||
mField.setText(null);
|
field.setText(null);
|
||||||
mField.requestFocus();
|
field.requestFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -262,7 +262,7 @@ public class UARTLogFragment extends ListFragment implements LoaderManager.Loade
|
|||||||
public void onServiceStarted() {
|
public void onServiceStarted() {
|
||||||
// The service has been started, bind to it
|
// The service has been started, bind to it
|
||||||
final Intent service = new Intent(getActivity(), UARTService.class);
|
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() {
|
public void onFragmentHidden() {
|
||||||
final InputMethodManager imm = (InputMethodManager) requireContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
final InputMethodManager imm = (InputMethodManager) requireContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||||
if (imm != null) {
|
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.
|
* Method called when the target device has connected.
|
||||||
*/
|
*/
|
||||||
protected void onDeviceConnected() {
|
protected void onDeviceConnected() {
|
||||||
mField.setEnabled(true);
|
field.setEnabled(true);
|
||||||
mSendButton.setEnabled(true);
|
sendButton.setEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method called when user disconnected from the target UART device or the connection was lost.
|
* Method called when user disconnected from the target UART device or the connection was lost.
|
||||||
*/
|
*/
|
||||||
protected void onDeviceDisconnected() {
|
protected void onDeviceDisconnected() {
|
||||||
mField.setEnabled(false);
|
field.setEnabled(false);
|
||||||
mSendButton.setEnabled(false);
|
sendButton.setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IntentFilter makeIntentFilter() {
|
private static IntentFilter makeIntentFilter() {
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public class UARTManager extends LoggableBleManager<UARTManagerCallbacks> {
|
|||||||
/** TX characteristic UUID */
|
/** TX characteristic UUID */
|
||||||
private final static UUID UART_TX_CHARACTERISTIC_UUID = UUID.fromString("6E400003-B5A3-F393-E0A9-E50E24DCCA9E");
|
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
|
* 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.
|
* 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.
|
* 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) {
|
UARTManager(final Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
@@ -60,39 +60,39 @@ public class UARTManager extends LoggableBleManager<UARTManagerCallbacks> {
|
|||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
protected BleManagerGattCallback getGattCallback() {
|
protected BleManagerGattCallback getGattCallback() {
|
||||||
return mGattCallback;
|
return gattCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BluetoothGatt callbacks for connection/disconnection, service discovery,
|
* BluetoothGatt callbacks for connection/disconnection, service discovery,
|
||||||
* receiving indication, etc.
|
* receiving indication, etc.
|
||||||
*/
|
*/
|
||||||
private final BleManagerGattCallback mGattCallback = new BleManagerGattCallback() {
|
private final BleManagerGattCallback gattCallback = new BleManagerGattCallback() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initialize() {
|
protected void initialize() {
|
||||||
setNotificationCallback(mTXCharacteristic)
|
setNotificationCallback(txCharacteristic)
|
||||||
.with((device, data) -> {
|
.with((device, data) -> {
|
||||||
final String text = data.getStringValue(0);
|
final String text = data.getStringValue(0);
|
||||||
log(LogContract.Log.Level.APPLICATION, "\"" + text + "\" received");
|
log(LogContract.Log.Level.APPLICATION, "\"" + text + "\" received");
|
||||||
mCallbacks.onDataReceived(device, text);
|
callbacks.onDataReceived(device, text);
|
||||||
});
|
});
|
||||||
requestMtu(260).enqueue();
|
requestMtu(260).enqueue();
|
||||||
enableNotifications(mTXCharacteristic).enqueue();
|
enableNotifications(txCharacteristic).enqueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) {
|
public boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) {
|
||||||
final BluetoothGattService service = gatt.getService(UART_SERVICE_UUID);
|
final BluetoothGattService service = gatt.getService(UART_SERVICE_UUID);
|
||||||
if (service != null) {
|
if (service != null) {
|
||||||
mRXCharacteristic = service.getCharacteristic(UART_RX_CHARACTERISTIC_UUID);
|
rxCharacteristic = service.getCharacteristic(UART_RX_CHARACTERISTIC_UUID);
|
||||||
mTXCharacteristic = service.getCharacteristic(UART_TX_CHARACTERISTIC_UUID);
|
txCharacteristic = service.getCharacteristic(UART_TX_CHARACTERISTIC_UUID);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean writeRequest = false;
|
boolean writeRequest = false;
|
||||||
boolean writeCommand = false;
|
boolean writeCommand = false;
|
||||||
if (mRXCharacteristic != null) {
|
if (rxCharacteristic != null) {
|
||||||
final int rxProperties = mRXCharacteristic.getProperties();
|
final int rxProperties = rxCharacteristic.getProperties();
|
||||||
writeRequest = (rxProperties & BluetoothGattCharacteristic.PROPERTY_WRITE) > 0;
|
writeRequest = (rxProperties & BluetoothGattCharacteristic.PROPERTY_WRITE) > 0;
|
||||||
writeCommand = (rxProperties & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) > 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
|
// 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.
|
// longer then MTU-3 bytes into up to MTU-3 bytes chunks.
|
||||||
if (writeRequest)
|
if (writeRequest)
|
||||||
mRXCharacteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
|
rxCharacteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
|
||||||
else
|
else
|
||||||
mUseLongWrite = false;
|
useLongWrite = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return mRXCharacteristic != null && mTXCharacteristic != null && (writeRequest || writeCommand);
|
return rxCharacteristic != null && txCharacteristic != null && (writeRequest || writeCommand);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDeviceDisconnected() {
|
protected void onDeviceDisconnected() {
|
||||||
mRXCharacteristic = null;
|
rxCharacteristic = null;
|
||||||
mTXCharacteristic = null;
|
txCharacteristic = null;
|
||||||
mUseLongWrite = true;
|
useLongWrite = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -130,14 +130,14 @@ public class UARTManager extends LoggableBleManager<UARTManagerCallbacks> {
|
|||||||
*/
|
*/
|
||||||
public void send(final String text) {
|
public void send(final String text) {
|
||||||
// Are we connected?
|
// Are we connected?
|
||||||
if (mRXCharacteristic == null)
|
if (rxCharacteristic == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(text)) {
|
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,
|
.with((device, data) -> log(LogContract.Log.Level.APPLICATION,
|
||||||
"\"" + data.getStringValue(0) + "\" sent"));
|
"\"" + data.getStringValue(0) + "\" sent"));
|
||||||
if (!mUseLongWrite) {
|
if (!useLongWrite) {
|
||||||
// This will automatically split the long data into MTU-3-byte long packets.
|
// This will automatically split the long data into MTU-3-byte long packets.
|
||||||
request.split();
|
request.split();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,11 +24,12 @@ package no.nordicsemi.android.nrftoolbox.uart;
|
|||||||
|
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import no.nordicsemi.android.ble.BleManagerCallbacks;
|
import no.nordicsemi.android.ble.BleManagerCallbacks;
|
||||||
|
|
||||||
public interface UARTManagerCallbacks extends 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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,9 +40,9 @@ public class UARTNewConfigurationDialogFragment extends DialogFragment implement
|
|||||||
private static final String NAME = "name";
|
private static final String NAME = "name";
|
||||||
private static final String DUPLICATE = "duplicate";
|
private static final String DUPLICATE = "duplicate";
|
||||||
|
|
||||||
private EditText mEditText;
|
private EditText editText;
|
||||||
|
|
||||||
private NewConfigurationDialogListener mListener;
|
private NewConfigurationDialogListener listener;
|
||||||
|
|
||||||
public interface NewConfigurationDialogListener {
|
public interface NewConfigurationDialogListener {
|
||||||
/**
|
/**
|
||||||
@@ -60,11 +60,11 @@ public class UARTNewConfigurationDialogFragment extends DialogFragment implement
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(final Context context) {
|
public void onAttach(@NonNull final Context context) {
|
||||||
super.onAttach(context);
|
super.onAttach(context);
|
||||||
|
|
||||||
if (context instanceof NewConfigurationDialogListener) {
|
if (context instanceof NewConfigurationDialogListener) {
|
||||||
mListener = (NewConfigurationDialogListener) context;
|
listener = (NewConfigurationDialogListener) context;
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("The parent activity must implement NewConfigurationDialogListener");
|
throw new IllegalArgumentException("The parent activity must implement NewConfigurationDialogListener");
|
||||||
}
|
}
|
||||||
@@ -73,7 +73,7 @@ public class UARTNewConfigurationDialogFragment extends DialogFragment implement
|
|||||||
@Override
|
@Override
|
||||||
public void onDetach() {
|
public void onDetach() {
|
||||||
super.onDetach();
|
super.onDetach();
|
||||||
mListener = null;
|
listener = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DialogFragment getInstance(final String name, final boolean duplicate) {
|
public static DialogFragment getInstance(final String name, final boolean duplicate) {
|
||||||
@@ -90,22 +90,25 @@ public class UARTNewConfigurationDialogFragment extends DialogFragment implement
|
|||||||
@Override
|
@Override
|
||||||
@NonNull
|
@NonNull
|
||||||
public Dialog onCreateDialog(final Bundle savedInstanceState) {
|
public Dialog onCreateDialog(final Bundle savedInstanceState) {
|
||||||
final Context context = getActivity();
|
final Bundle args = requireArguments();
|
||||||
|
|
||||||
final Bundle args = getArguments();
|
|
||||||
final String oldName = args.getString(NAME);
|
final String oldName = args.getString(NAME);
|
||||||
final boolean duplicate = args.getBoolean(DUPLICATE);
|
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 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 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));
|
editText.setText(args.getString(NAME));
|
||||||
final View actionClear = view.findViewById(R.id.action_clear);
|
final View actionClear = view.findViewById(R.id.action_clear);
|
||||||
actionClear.setOnClickListener(v -> editText.setText(null));
|
actionClear.setOnClickListener(v -> editText.setText(null));
|
||||||
|
|
||||||
final AlertDialog dialog = new AlertDialog.Builder(context).setTitle(titleResId).setView(view).setNegativeButton(R.string.cancel, null)
|
final AlertDialog dialog = new AlertDialog.Builder(requireContext())
|
||||||
.setPositiveButton(R.string.ok, null).setCancelable(false).show(); // this must be show() or the getButton() below will return null.
|
.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);
|
final Button okButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
|
||||||
okButton.setOnClickListener(this);
|
okButton.setOnClickListener(this);
|
||||||
@@ -115,19 +118,20 @@ public class UARTNewConfigurationDialogFragment extends DialogFragment implement
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(final View v) {
|
public void onClick(final View v) {
|
||||||
final String newName = mEditText.getText().toString().trim();
|
final String newName = editText.getText().toString().trim();
|
||||||
if (TextUtils.isEmpty(newName)) {
|
if (TextUtils.isEmpty(newName)) {
|
||||||
mEditText.setError(getString(R.string.uart_empty_name_error));
|
editText.setError(getString(R.string.uart_empty_name_error));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final String oldName = getArguments().getString(NAME);
|
final Bundle args = requireArguments();
|
||||||
final boolean duplicate = getArguments().getBoolean(DUPLICATE);
|
final String oldName = args.getString(NAME);
|
||||||
|
final boolean duplicate = args.getBoolean(DUPLICATE);
|
||||||
|
|
||||||
if (duplicate || TextUtils.isEmpty(oldName))
|
if (duplicate || TextUtils.isEmpty(oldName))
|
||||||
mListener.onNewConfiguration(newName, duplicate);
|
listener.onNewConfiguration(newName, duplicate);
|
||||||
else {
|
else {
|
||||||
mListener.onRenameConfiguration(newName);
|
listener.onRenameConfiguration(newName);
|
||||||
}
|
}
|
||||||
dismiss();
|
dismiss();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,26 +82,26 @@ public class UARTService extends BleProfileService implements UARTManagerCallbac
|
|||||||
private final static int OPEN_ACTIVITY_REQ = 67; // random
|
private final static int OPEN_ACTIVITY_REQ = 67; // random
|
||||||
private final static int DISCONNECT_REQ = 97; // random
|
private final static int DISCONNECT_REQ = 97; // random
|
||||||
|
|
||||||
private GoogleApiClient mGoogleApiClient;
|
private GoogleApiClient googleApiClient;
|
||||||
private UARTManager mManager;
|
private UARTManager manager;
|
||||||
|
|
||||||
private final LocalBinder mBinder = new UARTBinder();
|
private final LocalBinder binder = new UARTBinder();
|
||||||
|
|
||||||
public class UARTBinder extends LocalBinder implements UARTInterface {
|
public class UARTBinder extends LocalBinder implements UARTInterface {
|
||||||
@Override
|
@Override
|
||||||
public void send(final String text) {
|
public void send(final String text) {
|
||||||
mManager.send(text);
|
manager.send(text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected LocalBinder getBinder() {
|
protected LocalBinder getBinder() {
|
||||||
return mBinder;
|
return binder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected LoggableBleManager<UARTManagerCallbacks> initializeManager() {
|
protected LoggableBleManager<UARTManagerCallbacks> initializeManager() {
|
||||||
return mManager = new UARTManager(this);
|
return manager = new UARTManager(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -113,23 +113,23 @@ public class UARTService extends BleProfileService implements UARTManagerCallbac
|
|||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
|
|
||||||
registerReceiver(mDisconnectActionBroadcastReceiver, new IntentFilter(ACTION_DISCONNECT));
|
registerReceiver(disconnectActionBroadcastReceiver, new IntentFilter(ACTION_DISCONNECT));
|
||||||
registerReceiver(mIntentBroadcastReceiver, new IntentFilter(ACTION_SEND));
|
registerReceiver(intentBroadcastReceiver, new IntentFilter(ACTION_SEND));
|
||||||
|
|
||||||
mGoogleApiClient = new GoogleApiClient.Builder(this)
|
googleApiClient = new GoogleApiClient.Builder(this)
|
||||||
.addApi(Wearable.API)
|
.addApi(Wearable.API)
|
||||||
.build();
|
.build();
|
||||||
mGoogleApiClient.connect();
|
googleApiClient.connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
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
|
// when user has disconnected from the sensor, we have to cancel the notification that we've created some milliseconds before using unbindService
|
||||||
stopForegroundService();
|
stopForegroundService();
|
||||||
unregisterReceiver(mDisconnectActionBroadcastReceiver);
|
unregisterReceiver(disconnectActionBroadcastReceiver);
|
||||||
unregisterReceiver(mIntentBroadcastReceiver);
|
unregisterReceiver(intentBroadcastReceiver);
|
||||||
|
|
||||||
mGoogleApiClient.disconnect();
|
googleApiClient.disconnect();
|
||||||
|
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
}
|
}
|
||||||
@@ -174,7 +174,7 @@ public class UARTService extends BleProfileService implements UARTManagerCallbac
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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);
|
final Intent broadcast = new Intent(BROADCAST_UART_RX);
|
||||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||||
broadcast.putExtra(EXTRA_DATA, data);
|
broadcast.putExtra(EXTRA_DATA, data);
|
||||||
@@ -188,7 +188,7 @@ public class UARTService extends BleProfileService implements UARTManagerCallbac
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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);
|
final Intent broadcast = new Intent(BROADCAST_UART_TX);
|
||||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||||
broadcast.putExtra(EXTRA_DATA, data);
|
broadcast.putExtra(EXTRA_DATA, data);
|
||||||
@@ -201,13 +201,13 @@ public class UARTService extends BleProfileService implements UARTManagerCallbac
|
|||||||
* @param path message path
|
* @param path message path
|
||||||
* @param message the message
|
* @param message the message
|
||||||
*/
|
*/
|
||||||
private void sendMessageToWearables(final @NonNull String path, final @NonNull String message) {
|
private void sendMessageToWearables(@NonNull final String path, @NonNull final String message) {
|
||||||
if (mGoogleApiClient.isConnected()) {
|
if (googleApiClient.isConnected()) {
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).await();
|
NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
|
||||||
for (Node node : nodes.getNodes()) {
|
for (Node node : nodes.getNodes()) {
|
||||||
Logger.v(getLogSession(), "[WEAR] Sending message '" + path + "' to " + node.getDisplayName());
|
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()) {
|
if (result.getStatus().isSuccess()) {
|
||||||
Logger.i(getLogSession(), "[WEAR] Message sent");
|
Logger.i(getLogSession(), "[WEAR] Message sent");
|
||||||
} else {
|
} else {
|
||||||
@@ -259,6 +259,7 @@ public class UARTService extends BleProfileService implements UARTManagerCallbac
|
|||||||
* f.e. <code><string name="name">%s is connected</string></code>
|
* f.e. <code><string name="name">%s is connected</string></code>
|
||||||
* @param defaults signals that will be used to notify the user
|
* @param defaults signals that will be used to notify the user
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("SameParameterValue")
|
||||||
protected Notification createNotification(final int messageResId, final int defaults) {
|
protected Notification createNotification(final int messageResId, final int defaults) {
|
||||||
final Intent parentIntent = new Intent(this, FeaturesActivity.class);
|
final Intent parentIntent = new Intent(this, FeaturesActivity.class);
|
||||||
parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
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.
|
* 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
|
@Override
|
||||||
public void onReceive(final Context context, final Intent intent) {
|
public void onReceive(final Context context, final Intent intent) {
|
||||||
final int source = intent.getIntExtra(EXTRA_SOURCE, SOURCE_NOTIFICATION);
|
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.
|
* 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").
|
* The integer content will be sent as String (65 -> "65", not 65 -> "A").
|
||||||
*/
|
*/
|
||||||
private BroadcastReceiver mIntentBroadcastReceiver = new BroadcastReceiver() {
|
private BroadcastReceiver intentBroadcastReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(final Context context, final Intent intent) {
|
public void onReceive(final Context context, final Intent intent) {
|
||||||
final boolean hasMessage = intent.hasExtra(Intent.EXTRA_TEXT);
|
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 + "\"");
|
Logger.i(getLogSession(), "[Broadcast] " + ACTION_SEND + " broadcast received with data: \"" + message + "\"");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
mManager.send(message);
|
manager.send(message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import android.database.sqlite.SQLiteDatabase;
|
|||||||
import android.database.sqlite.SQLiteOpenHelper;
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
import android.provider.BaseColumns;
|
import android.provider.BaseColumns;
|
||||||
|
|
||||||
|
@SuppressWarnings("UnusedReturnValue")
|
||||||
public class DatabaseHelper {
|
public class DatabaseHelper {
|
||||||
/** Database file name */
|
/** Database file name */
|
||||||
private static final String DATABASE_NAME = "toolbox_uart.db";
|
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[] ID_PROJECTION = new String[] { BaseColumns._ID };
|
||||||
private static final String[] NAME_PROJECTION = new String[] { BaseColumns._ID, NameColumns.NAME };
|
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[] XML_PROJECTION = new String[] {
|
||||||
private static final String[] CONFIGURATION_PROJECTION = new String[] { BaseColumns._ID, NameColumns.NAME, ConfigurationContract.Configuration.XML };
|
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 ID_SELECTION = BaseColumns._ID + "=?";
|
||||||
private static final String NAME_SELECTION = NameColumns.NAME + "=?";
|
private static final String NAME_SELECTION = NameColumns.NAME + "=?";
|
||||||
private static final String DELETED_SELECTION = UndoColumns.DELETED + "=1";
|
private static final String DELETED_SELECTION = UndoColumns.DELETED + "=1";
|
||||||
private static final String NOT_DELETED_SELECTION = UndoColumns.DELETED + "=0";
|
private static final String NOT_DELETED_SELECTION = UndoColumns.DELETED + "=0";
|
||||||
|
|
||||||
private static SQLiteHelper mDatabaseHelper;
|
private static SQLiteHelper databaseHelper;
|
||||||
private static SQLiteDatabase mDatabase;
|
private static SQLiteDatabase database;
|
||||||
private final ContentValues mValues = new ContentValues();
|
private final ContentValues values = new ContentValues();
|
||||||
private final String[] mSingleArg = new String[1];
|
private final String[] singleArg = new String[1];
|
||||||
|
|
||||||
public DatabaseHelper(final Context context) {
|
public DatabaseHelper(final Context context) {
|
||||||
if (mDatabaseHelper == null) {
|
if (databaseHelper == null) {
|
||||||
mDatabaseHelper = new SQLiteHelper(context);
|
databaseHelper = new SQLiteHelper(context);
|
||||||
mDatabase = mDatabaseHelper.getWritableDatabase();
|
database = databaseHelper.getWritableDatabase();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,11 +70,9 @@ public class DatabaseHelper {
|
|||||||
* Returns number of saved configurations.
|
* Returns number of saved configurations.
|
||||||
*/
|
*/
|
||||||
public int getConfigurationsCount() {
|
public int getConfigurationsCount() {
|
||||||
final Cursor cursor = mDatabase.query(Tables.CONFIGURATIONS, ID_PROJECTION, NOT_DELETED_SELECTION, null, null, null, null);
|
try (Cursor cursor = database.query(Tables.CONFIGURATIONS, ID_PROJECTION, NOT_DELETED_SELECTION,
|
||||||
try {
|
null, null, null, null)) {
|
||||||
return cursor.getCount();
|
return cursor.getCount();
|
||||||
} finally {
|
|
||||||
cursor.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,91 +81,95 @@ public class DatabaseHelper {
|
|||||||
* @return cursor
|
* @return cursor
|
||||||
*/
|
*/
|
||||||
public Cursor getConfigurations() {
|
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.
|
* Returns the list of names of all saved configurations.
|
||||||
|
*
|
||||||
* @return cursor
|
* @return cursor
|
||||||
*/
|
*/
|
||||||
public Cursor getConfigurationsNames() {
|
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.
|
* Returns the XML wth the configuration by id.
|
||||||
|
*
|
||||||
* @param id the configuration id in the DB
|
* @param id the configuration id in the DB
|
||||||
* @return the XML with configuration or null
|
* @return the XML with configuration or null
|
||||||
*/
|
*/
|
||||||
public String getConfiguration(final long id) {
|
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 (Cursor cursor = database.query(Tables.CONFIGURATIONS, XML_PROJECTION, ID_SELECTION,
|
||||||
try {
|
singleArg, null, null, null)) {
|
||||||
if (cursor.moveToNext())
|
if (cursor.moveToNext())
|
||||||
return cursor.getString(1 /* XML */);
|
return cursor.getString(1 /* XML */);
|
||||||
return null;
|
return null;
|
||||||
} finally {
|
|
||||||
cursor.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds new configuration to the database.
|
* Adds new configuration to the database.
|
||||||
|
*
|
||||||
* @param name the configuration name
|
* @param name the configuration name
|
||||||
* @param configuration the XML
|
* @param configuration the XML
|
||||||
* @return the id or -1 if error occurred
|
* @return the id or -1 if error occurred
|
||||||
*/
|
*/
|
||||||
public long addConfiguration(final String name, final String configuration) {
|
public long addConfiguration(final String name, final String configuration) {
|
||||||
final ContentValues values = mValues;
|
final ContentValues values = this.values;
|
||||||
values.clear();
|
values.clear();
|
||||||
values.put(ConfigurationContract.Configuration.NAME, name);
|
values.put(ConfigurationContract.Configuration.NAME, name);
|
||||||
values.put(ConfigurationContract.Configuration.XML, configuration);
|
values.put(ConfigurationContract.Configuration.XML, configuration);
|
||||||
values.put(ConfigurationContract.Configuration.DELETED, 0);
|
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 name the configuration name to be updated
|
||||||
* @param configuration the new XML with configuration
|
* @param configuration the new XML with configuration
|
||||||
* @return number of rows updated
|
* @return number of rows updated
|
||||||
*/
|
*/
|
||||||
public int updateConfiguration(final String name, final String configuration) {
|
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.clear();
|
||||||
values.put(ConfigurationContract.Configuration.XML, configuration);
|
values.put(ConfigurationContract.Configuration.XML, configuration);
|
||||||
values.put(ConfigurationContract.Configuration.DELETED, 0);
|
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
|
* @param name the configuration name
|
||||||
* @return id of the deleted configuration
|
* @return id of the deleted configuration
|
||||||
*/
|
*/
|
||||||
public long deleteConfiguration(final String name) {
|
public long deleteConfiguration(final String name) {
|
||||||
mSingleArg[0] = name;
|
singleArg[0] = name;
|
||||||
|
|
||||||
final ContentValues values = mValues;
|
final ContentValues values = this.values;
|
||||||
values.clear();
|
values.clear();
|
||||||
values.put(ConfigurationContract.Configuration.DELETED, 1);
|
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 (Cursor cursor = database.query(Tables.CONFIGURATIONS, ID_PROJECTION, NAME_SELECTION,
|
||||||
try {
|
singleArg, null, null, null)) {
|
||||||
if (cursor.moveToNext())
|
if (cursor.moveToNext())
|
||||||
return cursor.getLong(0 /* _ID */);
|
return cursor.getLong(0 /* _ID */);
|
||||||
return -1;
|
return -1;
|
||||||
} finally {
|
|
||||||
cursor.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int removeDeletedServerConfigurations() {
|
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.
|
* @return the DI of the restored configuration.
|
||||||
*/
|
*/
|
||||||
public long restoreDeletedServerConfiguration(final String name) {
|
public long restoreDeletedServerConfiguration(final String name) {
|
||||||
mSingleArg[0] = name;
|
singleArg[0] = name;
|
||||||
|
|
||||||
final ContentValues values = mValues;
|
final ContentValues values = this.values;
|
||||||
values.clear();
|
values.clear();
|
||||||
values.put(ConfigurationContract.Configuration.DELETED, 0);
|
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 (Cursor cursor = database.query(Tables.CONFIGURATIONS, ID_PROJECTION, NAME_SELECTION, singleArg,
|
||||||
try {
|
null, null, null)) {
|
||||||
if (cursor.moveToNext())
|
if (cursor.moveToNext())
|
||||||
return cursor.getLong(0 /* _ID */);
|
return cursor.getLong(0 /* _ID */);
|
||||||
return -1;
|
return -1;
|
||||||
} finally {
|
|
||||||
cursor.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,13 +200,13 @@ public class DatabaseHelper {
|
|||||||
* @return number of rows affected
|
* @return number of rows affected
|
||||||
*/
|
*/
|
||||||
public int renameConfiguration(final String oldName, final String newName, final String configuration) {
|
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.clear();
|
||||||
values.put(ConfigurationContract.Configuration.NAME, newName);
|
values.put(ConfigurationContract.Configuration.NAME, newName);
|
||||||
values.put(ConfigurationContract.Configuration.XML, configuration);
|
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
|
* @return true if such name exists, false otherwise
|
||||||
*/
|
*/
|
||||||
public boolean configurationExists(final String name) {
|
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 (Cursor cursor = database.query(Tables.CONFIGURATIONS, NAME_PROJECTION, NAME_SELECTION
|
||||||
try {
|
+ " AND " + NOT_DELETED_SELECTION, singleArg, null, null, null)) {
|
||||||
return cursor.getCount() > 0;
|
return cursor.getCount() > 0;
|
||||||
} finally {
|
|
||||||
cursor.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,12 +236,13 @@ public class DatabaseHelper {
|
|||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
private static final String CREATE_CONFIGURATIONS = "CREATE TABLE " + Tables.CONFIGURATIONS+ "(" + ConfigurationContract.Configuration._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
|
private static final String CREATE_CONFIGURATIONS = "CREATE TABLE " + Tables.CONFIGURATIONS
|
||||||
+ ConfigurationContract.Configuration.NAME + " TEXT UNIQUE NOT NULL, " + ConfigurationContract.Configuration.XML + " TEXT NOT NULL, " + ConfigurationContract.Configuration.DELETED +" INTEGER NOT NULL DEFAULT(0))";
|
+ "(" + 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 ";
|
SQLiteHelper(Context context) {
|
||||||
|
|
||||||
public SQLiteHelper(Context context) {
|
|
||||||
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,6 +254,7 @@ public class DatabaseHelper {
|
|||||||
@Override
|
@Override
|
||||||
public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) {
|
public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) {
|
||||||
// This method does nothing for now.
|
// This method does nothing for now.
|
||||||
|
//noinspection SwitchStatementWithTooFewBranches
|
||||||
switch (oldVersion) {
|
switch (oldVersion) {
|
||||||
case 1:
|
case 1:
|
||||||
// do nothing
|
// do nothing
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ import no.nordicsemi.android.nrftoolbox.wearable.common.Constants;
|
|||||||
public class UARTConfigurationSynchronizer {
|
public class UARTConfigurationSynchronizer {
|
||||||
private static final String WEAR_URI_PREFIX = "wear:"; // no / at the end as the path already has it
|
private static final String WEAR_URI_PREFIX = "wear:"; // no / at the end as the path already has it
|
||||||
|
|
||||||
private static UARTConfigurationSynchronizer mInstance;
|
private static UARTConfigurationSynchronizer instance;
|
||||||
private GoogleApiClient mGoogleApiClient;
|
private GoogleApiClient googleApiClient;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the synchronizer.
|
* Initializes the synchronizer.
|
||||||
@@ -51,11 +51,11 @@ public class UARTConfigurationSynchronizer {
|
|||||||
* @param listener the connection callbacks listener
|
* @param listener the connection callbacks listener
|
||||||
*/
|
*/
|
||||||
public static UARTConfigurationSynchronizer from(final Context context, final GoogleApiClient.ConnectionCallbacks listener) {
|
public static UARTConfigurationSynchronizer from(final Context context, final GoogleApiClient.ConnectionCallbacks listener) {
|
||||||
if (mInstance == null)
|
if (instance == null)
|
||||||
mInstance = new UARTConfigurationSynchronizer();
|
instance = new UARTConfigurationSynchronizer();
|
||||||
|
|
||||||
mInstance.init(context, listener);
|
instance.init(context, listener);
|
||||||
return mInstance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
private UARTConfigurationSynchronizer() {
|
private UARTConfigurationSynchronizer() {
|
||||||
@@ -63,30 +63,31 @@ public class UARTConfigurationSynchronizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void init(final Context context, final GoogleApiClient.ConnectionCallbacks listener) {
|
private void init(final Context context, final GoogleApiClient.ConnectionCallbacks listener) {
|
||||||
if (mGoogleApiClient != null)
|
if (googleApiClient != null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mGoogleApiClient = new GoogleApiClient.Builder(context)
|
googleApiClient = new GoogleApiClient.Builder(context)
|
||||||
.addApiIfAvailable(Wearable.API)
|
.addApiIfAvailable(Wearable.API)
|
||||||
.addConnectionCallbacks(listener)
|
.addConnectionCallbacks(listener)
|
||||||
.build();
|
.build();
|
||||||
mGoogleApiClient.connect();
|
googleApiClient.connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes the synchronizer.
|
* Closes the synchronizer.
|
||||||
*/
|
*/
|
||||||
public void close() {
|
public void close() {
|
||||||
if (mGoogleApiClient != null)
|
if (googleApiClient != null)
|
||||||
mGoogleApiClient.disconnect();
|
googleApiClient.disconnect();
|
||||||
mGoogleApiClient = null;
|
googleApiClient = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if Wearable API has been connected.
|
* Returns true if Wearable API has been connected.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
||||||
public boolean hasConnectedApi() {
|
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);
|
map.putDataMapArrayList(Constants.UART.Configuration.COMMANDS, commands);
|
||||||
final PutDataRequest request = mapRequest.asPutDataRequest();
|
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.
|
* Call this when configuration has been deleted.
|
||||||
* @return pending result
|
* @return pending result
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("UnusedReturnValue")
|
||||||
public PendingResult<DataApi.DeleteDataItemsResult> onConfigurationDeleted(final long id) {
|
public PendingResult<DataApi.DeleteDataItemsResult> onConfigurationDeleted(final long id) {
|
||||||
if (!hasConnectedApi())
|
if (!hasConnectedApi())
|
||||||
return null;
|
return null;
|
||||||
return Wearable.DataApi.deleteDataItems(mGoogleApiClient, id2Uri(id));
|
return Wearable.DataApi.deleteDataItems(googleApiClient, id2Uri(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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.
|
// A disconnect message was sent. The information which profile should be disconnected is in the data.
|
||||||
final String profile = new String(messageEvent.getData());
|
final String profile = new String(messageEvent.getData());
|
||||||
|
|
||||||
|
//noinspection SwitchStatementWithTooFewBranches
|
||||||
switch (profile) {
|
switch (profile) {
|
||||||
// Currently only UART profile has Wear support
|
// Currently only UART profile has Wear support
|
||||||
case Constants.UART.PROFILE: {
|
case Constants.UART.PROFILE: {
|
||||||
|
|||||||
@@ -41,13 +41,13 @@ public class DividerItemDecoration extends RecyclerView.ItemDecoration {
|
|||||||
|
|
||||||
public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
|
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) {
|
public DividerItemDecoration(Context context, int orientation) {
|
||||||
final TypedArray a = context.obtainStyledAttributes(ATTRS);
|
final TypedArray a = context.obtainStyledAttributes(ATTRS);
|
||||||
mDivider = a.getDrawable(0);
|
divider = a.getDrawable(0);
|
||||||
a.recycle();
|
a.recycle();
|
||||||
setOrientation(orientation);
|
setOrientation(orientation);
|
||||||
}
|
}
|
||||||
@@ -56,12 +56,12 @@ public class DividerItemDecoration extends RecyclerView.ItemDecoration {
|
|||||||
if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
|
if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
|
||||||
throw new IllegalArgumentException("invalid orientation");
|
throw new IllegalArgumentException("invalid orientation");
|
||||||
}
|
}
|
||||||
mOrientation = orientation;
|
orientation = orientation;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
|
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
|
||||||
if (mOrientation == VERTICAL_LIST) {
|
if (orientation == VERTICAL_LIST) {
|
||||||
drawVertical(c, parent);
|
drawVertical(c, parent);
|
||||||
} else {
|
} else {
|
||||||
drawHorizontal(c, parent);
|
drawHorizontal(c, parent);
|
||||||
@@ -78,9 +78,9 @@ public class DividerItemDecoration extends RecyclerView.ItemDecoration {
|
|||||||
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
|
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
|
||||||
.getLayoutParams();
|
.getLayoutParams();
|
||||||
final int top = child.getBottom() + params.bottomMargin;
|
final int top = child.getBottom() + params.bottomMargin;
|
||||||
final int bottom = top + mDivider.getIntrinsicHeight();
|
final int bottom = top + divider.getIntrinsicHeight();
|
||||||
mDivider.setBounds(left, top, right, bottom);
|
divider.setBounds(left, top, right, bottom);
|
||||||
mDivider.draw(c);
|
divider.draw(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,18 +94,18 @@ public class DividerItemDecoration extends RecyclerView.ItemDecoration {
|
|||||||
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
|
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
|
||||||
.getLayoutParams();
|
.getLayoutParams();
|
||||||
final int left = child.getRight() + params.rightMargin;
|
final int left = child.getRight() + params.rightMargin;
|
||||||
final int right = left + mDivider.getIntrinsicHeight();
|
final int right = left + divider.getIntrinsicHeight();
|
||||||
mDivider.setBounds(left, top, right, bottom);
|
divider.setBounds(left, top, right, bottom);
|
||||||
mDivider.draw(c);
|
divider.draw(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
|
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
|
||||||
if (mOrientation == VERTICAL_LIST) {
|
if (orientation == VERTICAL_LIST) {
|
||||||
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
|
outRect.set(0, 0, 0, divider.getIntrinsicHeight());
|
||||||
} else {
|
} else {
|
||||||
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
|
outRect.set(0, 0, divider.getIntrinsicWidth(), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -38,9 +38,9 @@ import no.nordicsemi.android.nrftoolbox.R;
|
|||||||
|
|
||||||
public class ForegroundLinearLayout extends LinearLayout {
|
public class ForegroundLinearLayout extends LinearLayout {
|
||||||
|
|
||||||
private Drawable mForegroundSelector;
|
private Drawable foregroundSelector;
|
||||||
private Rect mRectPadding;
|
private Rect rectPadding;
|
||||||
private boolean mUseBackgroundPadding = false;
|
private boolean useBackgroundPadding = false;
|
||||||
|
|
||||||
public ForegroundLinearLayout(Context context) {
|
public ForegroundLinearLayout(Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
@@ -65,9 +65,9 @@ public class ForegroundLinearLayout extends LinearLayout {
|
|||||||
|
|
||||||
if (this.getBackground() instanceof NinePatchDrawable) {
|
if (this.getBackground() instanceof NinePatchDrawable) {
|
||||||
final NinePatchDrawable npd = (NinePatchDrawable) this.getBackground();
|
final NinePatchDrawable npd = (NinePatchDrawable) this.getBackground();
|
||||||
mRectPadding = new Rect();
|
rectPadding = new Rect();
|
||||||
if (npd.getPadding(mRectPadding)) {
|
if (npd.getPadding(rectPadding)) {
|
||||||
mUseBackgroundPadding = true;
|
useBackgroundPadding = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,8 +76,8 @@ public class ForegroundLinearLayout extends LinearLayout {
|
|||||||
protected void drawableStateChanged() {
|
protected void drawableStateChanged() {
|
||||||
super.drawableStateChanged();
|
super.drawableStateChanged();
|
||||||
|
|
||||||
if (mForegroundSelector != null && mForegroundSelector.isStateful()) {
|
if (foregroundSelector != null && foregroundSelector.isStateful()) {
|
||||||
mForegroundSelector.setState(getDrawableState());
|
foregroundSelector.setState(getDrawableState());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,11 +85,11 @@ public class ForegroundLinearLayout extends LinearLayout {
|
|||||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||||
super.onSizeChanged(w, h, oldw, oldh);
|
super.onSizeChanged(w, h, oldw, oldh);
|
||||||
|
|
||||||
if (mForegroundSelector != null) {
|
if (foregroundSelector != null) {
|
||||||
if (mUseBackgroundPadding) {
|
if (useBackgroundPadding) {
|
||||||
mForegroundSelector.setBounds(mRectPadding.left, mRectPadding.top, w - mRectPadding.right, h - mRectPadding.bottom);
|
foregroundSelector.setBounds(rectPadding.left, rectPadding.top, w - rectPadding.right, h - rectPadding.bottom);
|
||||||
} else {
|
} 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) {
|
protected void dispatchDraw(@NonNull Canvas canvas) {
|
||||||
super.dispatchDraw(canvas);
|
super.dispatchDraw(canvas);
|
||||||
|
|
||||||
if (mForegroundSelector != null) {
|
if (foregroundSelector != null) {
|
||||||
mForegroundSelector.draw(canvas);
|
foregroundSelector.draw(canvas);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean verifyDrawable(Drawable who) {
|
protected boolean verifyDrawable(Drawable who) {
|
||||||
return super.verifyDrawable(who) || (who == mForegroundSelector);
|
return super.verifyDrawable(who) || (who == foregroundSelector);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void jumpDrawablesToCurrentState() {
|
public void jumpDrawablesToCurrentState() {
|
||||||
super.jumpDrawablesToCurrentState();
|
super.jumpDrawablesToCurrentState();
|
||||||
if (mForegroundSelector != null) mForegroundSelector.jumpToCurrentState();
|
if (foregroundSelector != null) foregroundSelector.jumpToCurrentState();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setForeground(Drawable drawable) {
|
public void setForeground(Drawable drawable) {
|
||||||
if (mForegroundSelector != drawable) {
|
if (foregroundSelector != drawable) {
|
||||||
if (mForegroundSelector != null) {
|
if (foregroundSelector != null) {
|
||||||
mForegroundSelector.setCallback(null);
|
foregroundSelector.setCallback(null);
|
||||||
unscheduleDrawable(mForegroundSelector);
|
unscheduleDrawable(foregroundSelector);
|
||||||
}
|
}
|
||||||
|
|
||||||
mForegroundSelector = drawable;
|
foregroundSelector = drawable;
|
||||||
|
|
||||||
if (drawable != null) {
|
if (drawable != null) {
|
||||||
setWillNotDraw(false);
|
setWillNotDraw(false);
|
||||||
@@ -141,8 +141,8 @@ public class ForegroundLinearLayout extends LinearLayout {
|
|||||||
@Override
|
@Override
|
||||||
public void drawableHotspotChanged(float x, float y) {
|
public void drawableHotspotChanged(float x, float y) {
|
||||||
super.drawableHotspotChanged(x, y);
|
super.drawableHotspotChanged(x, y);
|
||||||
if (mForegroundSelector != null) {
|
if (foregroundSelector != null) {
|
||||||
mForegroundSelector.setHotspot(x, y);
|
foregroundSelector.setHotspot(x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -38,9 +38,9 @@ import no.nordicsemi.android.nrftoolbox.R;
|
|||||||
|
|
||||||
public class ForegroundRelativeLayout extends RelativeLayout {
|
public class ForegroundRelativeLayout extends RelativeLayout {
|
||||||
|
|
||||||
private Drawable mForegroundSelector;
|
private Drawable foregroundSelector;
|
||||||
private Rect mRectPadding;
|
private Rect rectPadding;
|
||||||
private boolean mUseBackgroundPadding = false;
|
private boolean useBackgroundPadding = false;
|
||||||
|
|
||||||
public ForegroundRelativeLayout(Context context) {
|
public ForegroundRelativeLayout(Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
@@ -65,9 +65,9 @@ public class ForegroundRelativeLayout extends RelativeLayout {
|
|||||||
|
|
||||||
if (this.getBackground() instanceof NinePatchDrawable) {
|
if (this.getBackground() instanceof NinePatchDrawable) {
|
||||||
final NinePatchDrawable npd = (NinePatchDrawable) this.getBackground();
|
final NinePatchDrawable npd = (NinePatchDrawable) this.getBackground();
|
||||||
mRectPadding = new Rect();
|
rectPadding = new Rect();
|
||||||
if (npd.getPadding(mRectPadding)) {
|
if (npd.getPadding(rectPadding)) {
|
||||||
mUseBackgroundPadding = true;
|
useBackgroundPadding = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,8 +76,8 @@ public class ForegroundRelativeLayout extends RelativeLayout {
|
|||||||
protected void drawableStateChanged() {
|
protected void drawableStateChanged() {
|
||||||
super.drawableStateChanged();
|
super.drawableStateChanged();
|
||||||
|
|
||||||
if (mForegroundSelector != null && mForegroundSelector.isStateful()) {
|
if (foregroundSelector != null && foregroundSelector.isStateful()) {
|
||||||
mForegroundSelector.setState(getDrawableState());
|
foregroundSelector.setState(getDrawableState());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,11 +85,11 @@ public class ForegroundRelativeLayout extends RelativeLayout {
|
|||||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||||
super.onSizeChanged(w, h, oldw, oldh);
|
super.onSizeChanged(w, h, oldw, oldh);
|
||||||
|
|
||||||
if (mForegroundSelector != null) {
|
if (foregroundSelector != null) {
|
||||||
if (mUseBackgroundPadding) {
|
if (useBackgroundPadding) {
|
||||||
mForegroundSelector.setBounds(mRectPadding.left, mRectPadding.top, w - mRectPadding.right, h - mRectPadding.bottom);
|
foregroundSelector.setBounds(rectPadding.left, rectPadding.top, w - rectPadding.right, h - rectPadding.bottom);
|
||||||
} else {
|
} 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) {
|
protected void dispatchDraw(@NonNull Canvas canvas) {
|
||||||
super.dispatchDraw(canvas);
|
super.dispatchDraw(canvas);
|
||||||
|
|
||||||
if (mForegroundSelector != null) {
|
if (foregroundSelector != null) {
|
||||||
mForegroundSelector.draw(canvas);
|
foregroundSelector.draw(canvas);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean verifyDrawable(Drawable who) {
|
protected boolean verifyDrawable(Drawable who) {
|
||||||
return super.verifyDrawable(who) || (who == mForegroundSelector);
|
return super.verifyDrawable(who) || (who == foregroundSelector);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void jumpDrawablesToCurrentState() {
|
public void jumpDrawablesToCurrentState() {
|
||||||
super.jumpDrawablesToCurrentState();
|
super.jumpDrawablesToCurrentState();
|
||||||
if (mForegroundSelector != null) mForegroundSelector.jumpToCurrentState();
|
if (foregroundSelector != null) foregroundSelector.jumpToCurrentState();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setForeground(Drawable drawable) {
|
public void setForeground(Drawable drawable) {
|
||||||
if (mForegroundSelector != drawable) {
|
if (foregroundSelector != drawable) {
|
||||||
if (mForegroundSelector != null) {
|
if (foregroundSelector != null) {
|
||||||
mForegroundSelector.setCallback(null);
|
foregroundSelector.setCallback(null);
|
||||||
unscheduleDrawable(mForegroundSelector);
|
unscheduleDrawable(foregroundSelector);
|
||||||
}
|
}
|
||||||
|
|
||||||
mForegroundSelector = drawable;
|
foregroundSelector = drawable;
|
||||||
|
|
||||||
if (drawable != null) {
|
if (drawable != null) {
|
||||||
setWillNotDraw(false);
|
setWillNotDraw(false);
|
||||||
@@ -141,8 +141,8 @@ public class ForegroundRelativeLayout extends RelativeLayout {
|
|||||||
@Override
|
@Override
|
||||||
public void drawableHotspotChanged(float x, float y) {
|
public void drawableHotspotChanged(float x, float y) {
|
||||||
super.drawableHotspotChanged(x, y);
|
super.drawableHotspotChanged(x, y);
|
||||||
if (mForegroundSelector != null) {
|
if (foregroundSelector != null) {
|
||||||
mForegroundSelector.setHotspot(x, y);
|
foregroundSelector.setHotspot(x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -41,19 +41,19 @@ public class DeviceItemLayout extends RelativeLayout implements WearableListView
|
|||||||
private static final float SHRINK_LABEL_ALPHA = .5f;
|
private static final float SHRINK_LABEL_ALPHA = .5f;
|
||||||
private static final float EXPAND_LABEL_ALPHA = 1f;
|
private static final float EXPAND_LABEL_ALPHA = 1f;
|
||||||
|
|
||||||
private float mExpandCircleRadius;
|
private float expandCircleRadius;
|
||||||
private float mShrinkCircleRadius;
|
private float shrinkCircleRadius;
|
||||||
|
|
||||||
private ObjectAnimator mExpandCircleAnimator;
|
private ObjectAnimator expandCircleAnimator;
|
||||||
private ObjectAnimator mFadeInLabelAnimator;
|
private ObjectAnimator fadeInLabelAnimator;
|
||||||
private AnimatorSet mExpandAnimator;
|
private AnimatorSet expandAnimator;
|
||||||
|
|
||||||
private ObjectAnimator mShrinkCircleAnimator;
|
private ObjectAnimator shrinkCircleAnimator;
|
||||||
private ObjectAnimator mFadeOutLabelAnimator;
|
private ObjectAnimator fadeOutLabelAnimator;
|
||||||
private AnimatorSet mShrinkAnimator;
|
private AnimatorSet shrinkAnimator;
|
||||||
|
|
||||||
private TextView mName;
|
private TextView name;
|
||||||
private CircledImageView mIcon;
|
private CircledImageView icon;
|
||||||
|
|
||||||
public DeviceItemLayout(final Context context) {
|
public DeviceItemLayout(final Context context) {
|
||||||
this(context, null, 0);
|
this(context, null, 0);
|
||||||
@@ -71,51 +71,51 @@ public class DeviceItemLayout extends RelativeLayout implements WearableListView
|
|||||||
protected void onFinishInflate() {
|
protected void onFinishInflate() {
|
||||||
super.onFinishInflate();
|
super.onFinishInflate();
|
||||||
|
|
||||||
mName = findViewById(R.id.name);
|
name = findViewById(R.id.name);
|
||||||
mIcon = findViewById(R.id.icon);
|
icon = findViewById(R.id.icon);
|
||||||
mExpandCircleRadius = mIcon.getCircleRadius();
|
expandCircleRadius = icon.getCircleRadius();
|
||||||
mShrinkCircleRadius = mExpandCircleRadius * SHRINK_CIRCLE_RATIO;
|
shrinkCircleRadius = expandCircleRadius * SHRINK_CIRCLE_RATIO;
|
||||||
|
|
||||||
mShrinkCircleAnimator = ObjectAnimator.ofFloat(mIcon, "circleRadius", mExpandCircleRadius, mShrinkCircleRadius);
|
shrinkCircleAnimator = ObjectAnimator.ofFloat(icon, "circleRadius", expandCircleRadius, shrinkCircleRadius);
|
||||||
mFadeOutLabelAnimator = ObjectAnimator.ofFloat(mName, "alpha", EXPAND_LABEL_ALPHA, SHRINK_LABEL_ALPHA);
|
fadeOutLabelAnimator = ObjectAnimator.ofFloat(name, "alpha", EXPAND_LABEL_ALPHA, SHRINK_LABEL_ALPHA);
|
||||||
mShrinkAnimator = new AnimatorSet().setDuration(ANIMATION_DURATION_MS);
|
shrinkAnimator = new AnimatorSet().setDuration(ANIMATION_DURATION_MS);
|
||||||
mShrinkAnimator.playTogether(mShrinkCircleAnimator, mFadeOutLabelAnimator);
|
shrinkAnimator.playTogether(shrinkCircleAnimator, fadeOutLabelAnimator);
|
||||||
|
|
||||||
mExpandCircleAnimator = ObjectAnimator.ofFloat(mIcon, "circleRadius", mShrinkCircleRadius, mExpandCircleRadius);
|
expandCircleAnimator = ObjectAnimator.ofFloat(icon, "circleRadius", shrinkCircleRadius, expandCircleRadius);
|
||||||
mFadeInLabelAnimator = ObjectAnimator.ofFloat(mName, "alpha", SHRINK_LABEL_ALPHA, EXPAND_LABEL_ALPHA);
|
fadeInLabelAnimator = ObjectAnimator.ofFloat(name, "alpha", SHRINK_LABEL_ALPHA, EXPAND_LABEL_ALPHA);
|
||||||
mExpandAnimator = new AnimatorSet().setDuration(ANIMATION_DURATION_MS);
|
expandAnimator = new AnimatorSet().setDuration(ANIMATION_DURATION_MS);
|
||||||
mExpandAnimator.playTogether(mExpandCircleAnimator, mFadeInLabelAnimator);
|
expandAnimator.playTogether(expandCircleAnimator, fadeInLabelAnimator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCenterPosition(final boolean animate) {
|
public void onCenterPosition(final boolean animate) {
|
||||||
if (animate) {
|
if (animate) {
|
||||||
mShrinkAnimator.cancel();
|
shrinkAnimator.cancel();
|
||||||
if (!mExpandAnimator.isRunning()) {
|
if (!expandAnimator.isRunning()) {
|
||||||
mExpandCircleAnimator.setFloatValues(mIcon.getCircleRadius(), mExpandCircleRadius);
|
expandCircleAnimator.setFloatValues(icon.getCircleRadius(), expandCircleRadius);
|
||||||
mFadeInLabelAnimator.setFloatValues(mName.getAlpha(), EXPAND_LABEL_ALPHA);
|
fadeInLabelAnimator.setFloatValues(name.getAlpha(), EXPAND_LABEL_ALPHA);
|
||||||
mExpandAnimator.start();
|
expandAnimator.start();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mExpandAnimator.cancel();
|
expandAnimator.cancel();
|
||||||
mIcon.setCircleRadius(mExpandCircleRadius);
|
icon.setCircleRadius(expandCircleRadius);
|
||||||
mName.setAlpha(EXPAND_LABEL_ALPHA);
|
name.setAlpha(EXPAND_LABEL_ALPHA);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNonCenterPosition(final boolean animate) {
|
public void onNonCenterPosition(final boolean animate) {
|
||||||
if (animate) {
|
if (animate) {
|
||||||
mExpandAnimator.cancel();
|
expandAnimator.cancel();
|
||||||
if (!mShrinkAnimator.isRunning()) {
|
if (!shrinkAnimator.isRunning()) {
|
||||||
mShrinkCircleAnimator.setFloatValues(mIcon.getCircleRadius(), mShrinkCircleRadius);
|
shrinkCircleAnimator.setFloatValues(icon.getCircleRadius(), shrinkCircleRadius);
|
||||||
mFadeOutLabelAnimator.setFloatValues(mName.getAlpha(), SHRINK_LABEL_ALPHA);
|
fadeOutLabelAnimator.setFloatValues(name.getAlpha(), SHRINK_LABEL_ALPHA);
|
||||||
mShrinkAnimator.start();
|
shrinkAnimator.start();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mShrinkAnimator.cancel();
|
shrinkAnimator.cancel();
|
||||||
mIcon.setCircleRadius(mShrinkCircleRadius);
|
icon.setCircleRadius(shrinkCircleRadius);
|
||||||
mName.setAlpha(SHRINK_LABEL_ALPHA);
|
name.setAlpha(SHRINK_LABEL_ALPHA);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,127 +48,127 @@ public class DevicesAdapter extends WearableListView.Adapter {
|
|||||||
|
|
||||||
private final static long SCAN_DURATION = 5000;
|
private final static long SCAN_DURATION = 5000;
|
||||||
|
|
||||||
private final List<BluetoothDevice> mDevices = new ArrayList<>();
|
private final List<BluetoothDevice> devices = new ArrayList<>();
|
||||||
private final LayoutInflater mInflater;
|
private final LayoutInflater inflater;
|
||||||
private final Handler mHandler;
|
private final Handler handler;
|
||||||
private final WearableListView mListView;
|
private final WearableListView listView;
|
||||||
private final String mNotAvailable;
|
private final String notAvailable;
|
||||||
private final String mConnectingText;
|
private final String connectingText;
|
||||||
private final String mAvailableText;
|
private final String availableText;
|
||||||
private final String mBondedText;
|
private final String bondedText;
|
||||||
private final String mBondingText;
|
private final String bondingText;
|
||||||
/** A position of a device that the activity is currently connecting to. */
|
/** 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. */
|
/** Flag set to true when scanner is active. */
|
||||||
private boolean mScanning;
|
private boolean scanning;
|
||||||
|
|
||||||
public DevicesAdapter(final WearableListView listView) {
|
public DevicesAdapter(final WearableListView listView) {
|
||||||
final Context context = listView.getContext();
|
final Context context = listView.getContext();
|
||||||
mInflater = LayoutInflater.from(context);
|
inflater = LayoutInflater.from(context);
|
||||||
mNotAvailable = context.getString(R.string.not_available);
|
notAvailable = context.getString(R.string.not_available);
|
||||||
mConnectingText = context.getString(R.string.state_connecting);
|
connectingText = context.getString(R.string.state_connecting);
|
||||||
mAvailableText = context.getString(R.string.devices_list_available);
|
availableText = context.getString(R.string.devices_list_available);
|
||||||
mBondedText = context.getString(R.string.devices_list_bonded);
|
bondedText = context.getString(R.string.devices_list_bonded);
|
||||||
mBondingText = context.getString(R.string.devices_list_bonding);
|
bondingText = context.getString(R.string.devices_list_bonding);
|
||||||
mListView = listView;
|
this.listView = listView;
|
||||||
mHandler = new Handler();
|
handler = new Handler();
|
||||||
|
|
||||||
final BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
final BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||||
if (bluetoothAdapter != null)
|
if (bluetoothAdapter != null)
|
||||||
mDevices.addAll(bluetoothAdapter.getBondedDevices());
|
devices.addAll(bluetoothAdapter.getBondedDevices());
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public WearableListView.ViewHolder onCreateViewHolder(@NonNull final ViewGroup viewGroup, final int position) {
|
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
|
@Override
|
||||||
public void onBindViewHolder(@NonNull final WearableListView.ViewHolder holder, final int position) {
|
public void onBindViewHolder(@NonNull final WearableListView.ViewHolder holder, final int position) {
|
||||||
final ItemViewHolder viewHolder = (ItemViewHolder) holder;
|
final ItemViewHolder viewHolder = (ItemViewHolder) holder;
|
||||||
|
|
||||||
if (position < mDevices.size()) {
|
if (position < devices.size()) {
|
||||||
final BluetoothDevice device = mDevices.get(position);
|
final BluetoothDevice device = devices.get(position);
|
||||||
|
|
||||||
viewHolder.mDevice = device;
|
viewHolder.device = device;
|
||||||
viewHolder.mName.setText(TextUtils.isEmpty(device.getName()) ? mNotAvailable : device.getName());
|
viewHolder.name.setText(TextUtils.isEmpty(device.getName()) ? notAvailable : device.getName());
|
||||||
viewHolder.mAddress.setText(getState(device, position));
|
viewHolder.address.setText(getState(device, position));
|
||||||
viewHolder.mIcon.showIndeterminateProgress(position == mConnectingPosition);
|
viewHolder.icon.showIndeterminateProgress(position == connectingPosition);
|
||||||
} else {
|
} else {
|
||||||
viewHolder.mDevice = null;
|
viewHolder.device = null;
|
||||||
viewHolder.mName.setText(mScanning ? R.string.devices_list_scanning : R.string.devices_list_start_scan);
|
viewHolder.name.setText(scanning ? R.string.devices_list_scanning : R.string.devices_list_start_scan);
|
||||||
viewHolder.mAddress.setText(null);
|
viewHolder.address.setText(null);
|
||||||
viewHolder.mIcon.showIndeterminateProgress(mScanning);
|
viewHolder.icon.showIndeterminateProgress(scanning);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getItemCount() {
|
public int getItemCount() {
|
||||||
return mDevices.size() + (mConnectingPosition == -1 ? 1 : 0);
|
return devices.size() + (connectingPosition == -1 ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setConnectingPosition(final int connectingPosition) {
|
public void setConnectingPosition(final int connectingPosition) {
|
||||||
final int oldPosition = mConnectingPosition;
|
final int oldPosition = connectingPosition;
|
||||||
this.mConnectingPosition = connectingPosition;
|
this.connectingPosition = connectingPosition;
|
||||||
if (connectingPosition >= 0) {
|
if (connectingPosition >= 0) {
|
||||||
// The "Scan for nearby device' item is removed
|
// The "Scan for nearby device' item is removed
|
||||||
notifyItemChanged(connectingPosition);
|
notifyItemChanged(connectingPosition);
|
||||||
notifyItemRemoved(mDevices.size());
|
notifyItemRemoved(devices.size());
|
||||||
} else {
|
} else {
|
||||||
if (oldPosition >= 0)
|
if (oldPosition >= 0)
|
||||||
notifyItemChanged(oldPosition);
|
notifyItemChanged(oldPosition);
|
||||||
notifyItemInserted(mDevices.size());
|
notifyItemInserted(devices.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startLeScan() {
|
public void startLeScan() {
|
||||||
// Scanning is disabled when we are connecting or connected.
|
// Scanning is disabled when we are connecting or connected.
|
||||||
if (mConnectingPosition >= 0)
|
if (connectingPosition >= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (mScanning) {
|
if (scanning) {
|
||||||
// Extend scanning for some time more
|
// Extend scanning for some time more
|
||||||
mHandler.removeCallbacks(mStopScanTask);
|
handler.removeCallbacks(stopScanTask);
|
||||||
mHandler.postDelayed(mStopScanTask, SCAN_DURATION);
|
handler.postDelayed(stopScanTask, SCAN_DURATION);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final BluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();
|
final BluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();
|
||||||
final ScanSettings settings = new ScanSettings.Builder().setReportDelay(1000).setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();
|
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
|
// Setup timer that will stop scanning
|
||||||
mHandler.postDelayed(mStopScanTask, SCAN_DURATION);
|
handler.postDelayed(stopScanTask, SCAN_DURATION);
|
||||||
mScanning = true;
|
scanning = true;
|
||||||
notifyItemChanged(mDevices.size());
|
notifyItemChanged(devices.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stopLeScan() {
|
public void stopLeScan() {
|
||||||
if (!mScanning)
|
if (!scanning)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
final BluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();
|
final BluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();
|
||||||
scanner.stopScan(mScanCallback);
|
scanner.stopScan(scanCallback);
|
||||||
|
|
||||||
mHandler.removeCallbacks(mStopScanTask);
|
handler.removeCallbacks(stopScanTask);
|
||||||
mScanning = false;
|
scanning = false;
|
||||||
notifyItemChanged(mDevices.size());
|
notifyItemChanged(devices.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getState(final BluetoothDevice device, final int position) {
|
private String getState(final BluetoothDevice device, final int position) {
|
||||||
if (mConnectingPosition == position)
|
if (connectingPosition == position)
|
||||||
return mConnectingText;
|
return connectingText;
|
||||||
else if (device.getBondState() == BluetoothDevice.BOND_BONDED)
|
else if (device.getBondState() == BluetoothDevice.BOND_BONDED)
|
||||||
return mBondedText;
|
return bondedText;
|
||||||
else if (device.getBondState() == BluetoothDevice.BOND_BONDING)
|
else if (device.getBondState() == BluetoothDevice.BOND_BONDING)
|
||||||
return mBondingText;
|
return bondingText;
|
||||||
return mAvailableText;
|
return availableText;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Runnable mStopScanTask = this::stopLeScan;
|
private Runnable stopScanTask = this::stopLeScan;
|
||||||
|
|
||||||
private ScanCallback mScanCallback = new ScanCallback() {
|
private ScanCallback scanCallback = new ScanCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onScanResult(final int callbackType, @NonNull final ScanResult result) {
|
public void onScanResult(final int callbackType, @NonNull final ScanResult result) {
|
||||||
// empty
|
// empty
|
||||||
@@ -176,16 +176,16 @@ public class DevicesAdapter extends WearableListView.Adapter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBatchScanResults(final List<ScanResult> results) {
|
public void onBatchScanResults(final List<ScanResult> results) {
|
||||||
final int size = mDevices.size();
|
final int size = devices.size();
|
||||||
for (final ScanResult result : results) {
|
for (final ScanResult result : results) {
|
||||||
final BluetoothDevice device = result.getDevice();
|
final BluetoothDevice device = result.getDevice();
|
||||||
if (!mDevices.contains(device))
|
if (!devices.contains(device))
|
||||||
mDevices.add(device);
|
devices.add(device);
|
||||||
}
|
}
|
||||||
if (size != mDevices.size()) {
|
if (size != devices.size()) {
|
||||||
notifyItemRangeInserted(size, mDevices.size() - size);
|
notifyItemRangeInserted(size, devices.size() - size);
|
||||||
if (size == 0)
|
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 {
|
public static class ItemViewHolder extends WearableListView.ViewHolder {
|
||||||
private CircledImageView mIcon;
|
private CircledImageView icon;
|
||||||
private TextView mName;
|
private TextView name;
|
||||||
private TextView mAddress;
|
private TextView address;
|
||||||
private BluetoothDevice mDevice;
|
private BluetoothDevice device;
|
||||||
|
|
||||||
public ItemViewHolder(final View itemView) {
|
public ItemViewHolder(final View itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
|
|
||||||
mIcon = itemView.findViewById(R.id.icon);
|
icon = itemView.findViewById(R.id.icon);
|
||||||
mName = itemView.findViewById(R.id.name);
|
name = itemView.findViewById(R.id.name);
|
||||||
mAddress = itemView.findViewById(R.id.state);
|
address = itemView.findViewById(R.id.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the Bluetooth device for that holder, or null for "Scanning for nearby devices" row. */
|
/** Returns the Bluetooth device for that holder, or null for "Scanning for nearby devices" row. */
|
||||||
public BluetoothDevice getDevice() {
|
public BluetoothDevice getDevice() {
|
||||||
return mDevice;
|
return device;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,10 +45,10 @@ public class ScannerActivity extends Activity {
|
|||||||
|
|
||||||
private static final int PERMISSION_REQUEST_LOCATION = 1;
|
private static final int PERMISSION_REQUEST_LOCATION = 1;
|
||||||
|
|
||||||
private DevicesAdapter mDeviceAdapter;
|
private DevicesAdapter deviceAdapter;
|
||||||
private View mHeader;
|
private View header;
|
||||||
|
|
||||||
private BroadcastReceiver mServiceBroadcastReceiver = new BroadcastReceiver() {
|
private BroadcastReceiver serviceBroadcastReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(final Context context, final Intent intent) {
|
public void onReceive(final Context context, final Intent intent) {
|
||||||
final String action = intent.getAction();
|
final String action = intent.getAction();
|
||||||
@@ -57,7 +57,7 @@ public class ScannerActivity extends Activity {
|
|||||||
case BleProfileService.BROADCAST_CONNECTION_STATE: {
|
case BleProfileService.BROADCAST_CONNECTION_STATE: {
|
||||||
final int state = intent.getIntExtra(BleProfileService.EXTRA_CONNECTION_STATE, BleProfileService.STATE_DISCONNECTED);
|
final int state = intent.getIntExtra(BleProfileService.EXTRA_CONNECTION_STATE, BleProfileService.STATE_DISCONNECTED);
|
||||||
if (state == BleProfileService.STATE_DISCONNECTED)
|
if (state == BleProfileService.STATE_DISCONNECTED)
|
||||||
mDeviceAdapter.setConnectingPosition(-1);
|
deviceAdapter.setConnectingPosition(-1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BleProfileService.BROADCAST_DEVICE_READY: {
|
case BleProfileService.BROADCAST_DEVICE_READY: {
|
||||||
@@ -68,7 +68,7 @@ public class ScannerActivity extends Activity {
|
|||||||
}
|
}
|
||||||
case BleProfileService.BROADCAST_DEVICE_NOT_SUPPORTED: {
|
case BleProfileService.BROADCAST_DEVICE_NOT_SUPPORTED: {
|
||||||
Toast.makeText(ScannerActivity.this, R.string.devices_list_device_not_supported, Toast.LENGTH_SHORT).show();
|
Toast.makeText(ScannerActivity.this, R.string.devices_list_device_not_supported, Toast.LENGTH_SHORT).show();
|
||||||
mDeviceAdapter.setConnectingPosition(-1);
|
deviceAdapter.setConnectingPosition(-1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BleProfileService.BROADCAST_ERROR: {
|
case BleProfileService.BROADCAST_ERROR: {
|
||||||
@@ -79,7 +79,7 @@ public class ScannerActivity extends Activity {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BleProfileService.BROADCAST_BOND_STATE: {
|
case BleProfileService.BROADCAST_BOND_STATE: {
|
||||||
mDeviceAdapter.notifyDataSetChanged(); // TODO check this. Bonding was never tested.
|
deviceAdapter.notifyDataSetChanged(); // TODO check this. Bonding was never tested.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -93,21 +93,21 @@ public class ScannerActivity extends Activity {
|
|||||||
|
|
||||||
// Get the list component from the layout of the activity
|
// Get the list component from the layout of the activity
|
||||||
final WearableListView listView = findViewById(R.id.devices_list);
|
final WearableListView listView = findViewById(R.id.devices_list);
|
||||||
listView.setAdapter(mDeviceAdapter = new DevicesAdapter(listView));
|
listView.setAdapter(deviceAdapter = new DevicesAdapter(listView));
|
||||||
listView.setClickListener(mOnRowClickListener);
|
listView.setClickListener(onRowClickListener);
|
||||||
listView.addOnScrollListener(mOnScrollListener);
|
listView.addOnScrollListener(onScrollListener);
|
||||||
|
|
||||||
// The header will be moved as the list is scrolled
|
// 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.
|
// 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
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(mServiceBroadcastReceiver);
|
LocalBroadcastManager.getInstance(this).unregisterReceiver(serviceBroadcastReceiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -115,7 +115,7 @@ public class ScannerActivity extends Activity {
|
|||||||
switch (requestCode) {
|
switch (requestCode) {
|
||||||
case PERMISSION_REQUEST_LOCATION:
|
case PERMISSION_REQUEST_LOCATION:
|
||||||
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||||
mDeviceAdapter.startLeScan();
|
deviceAdapter.startLeScan();
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(ScannerActivity.this, "Location permission required", Toast.LENGTH_SHORT).show();
|
Toast.makeText(ScannerActivity.this, "Location permission required", Toast.LENGTH_SHORT).show();
|
||||||
finish();
|
finish();
|
||||||
@@ -134,32 +134,32 @@ public class ScannerActivity extends Activity {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mDeviceAdapter.startLeScan();
|
deviceAdapter.startLeScan();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPause() {
|
protected void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
mDeviceAdapter.stopLeScan();
|
deviceAdapter.stopLeScan();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** List click listener. */
|
/** List click listener. */
|
||||||
private WearableListView.ClickListener mOnRowClickListener = new WearableListView.ClickListener() {
|
private WearableListView.ClickListener onRowClickListener = new WearableListView.ClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(final WearableListView.ViewHolder holder) {
|
public void onClick(final WearableListView.ViewHolder holder) {
|
||||||
final DevicesAdapter.ItemViewHolder viewHolder = (DevicesAdapter.ItemViewHolder) holder;
|
final DevicesAdapter.ItemViewHolder viewHolder = (DevicesAdapter.ItemViewHolder) holder;
|
||||||
final BluetoothDevice device = viewHolder.getDevice();
|
final BluetoothDevice device = viewHolder.getDevice();
|
||||||
|
|
||||||
if (device != null) {
|
if (device != null) {
|
||||||
mDeviceAdapter.stopLeScan();
|
deviceAdapter.stopLeScan();
|
||||||
mDeviceAdapter.setConnectingPosition(holder.getAdapterPosition());
|
deviceAdapter.setConnectingPosition(holder.getAdapterPosition());
|
||||||
|
|
||||||
// Start the service that will connect to selected device
|
// Start the service that will connect to selected device
|
||||||
final Intent service = new Intent(ScannerActivity.this, BleProfileService.class);
|
final Intent service = new Intent(ScannerActivity.this, BleProfileService.class);
|
||||||
service.putExtra(BleProfileService.EXTRA_DEVICE_ADDRESS, device.getAddress());
|
service.putExtra(BleProfileService.EXTRA_DEVICE_ADDRESS, device.getAddress());
|
||||||
startService(service);
|
startService(service);
|
||||||
} else {
|
} 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/ */
|
/** 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
|
@Override
|
||||||
public void onAbsoluteScrollChange(final int i) {
|
public void onAbsoluteScrollChange(final int i) {
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
mHeader.setY(-i);
|
header.setY(-i);
|
||||||
else
|
else
|
||||||
mHeader.setY(0);
|
header.setY(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -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 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 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;
|
protected final BleManagerCallbacks callbacks;
|
||||||
private final Context mContext;
|
private final Context context;
|
||||||
private final Handler mHandler;
|
private final Handler handler;
|
||||||
protected BluetoothDevice mBluetoothDevice;
|
protected BluetoothDevice bluetoothDevice;
|
||||||
protected BleProfile mProfile;
|
protected BleProfile profile;
|
||||||
private BluetoothGatt mBluetoothGatt;
|
private BluetoothGatt bluetoothGatt;
|
||||||
private BleManagerGattCallback mGattCallback;
|
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.
|
* 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.
|
* 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 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.
|
* 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.
|
* 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. */
|
/** Flag set to true when the device is connected. */
|
||||||
private boolean mConnected;
|
private boolean connected;
|
||||||
private int mConnectionState = BluetoothGatt.STATE_DISCONNECTED;
|
private int connectionState = BluetoothGatt.STATE_DISCONNECTED;
|
||||||
/** Last received battery value or -1 if value wasn't received. */
|
/** 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.
|
* 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
|
@Override
|
||||||
public void onReceive(final Context context, final Intent intent) {
|
public void onReceive(final Context context, final Intent intent) {
|
||||||
final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF);
|
final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF);
|
||||||
@@ -115,9 +115,9 @@ public class BleManager implements BleProfileApi {
|
|||||||
switch (state) {
|
switch (state) {
|
||||||
case BluetoothAdapter.STATE_TURNING_OFF:
|
case BluetoothAdapter.STATE_TURNING_OFF:
|
||||||
case BluetoothAdapter.STATE_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
|
// The connection is killed by the system, no need to gently disconnect
|
||||||
mGattCallback.notifyDeviceDisconnected(mBluetoothDevice);
|
gattCallback.notifyDeviceDisconnected(bluetoothDevice);
|
||||||
}
|
}
|
||||||
close();
|
close();
|
||||||
break;
|
break;
|
||||||
@@ -125,7 +125,7 @@ public class BleManager implements BleProfileApi {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private BroadcastReceiver mBondingBroadcastReceiver = new BroadcastReceiver() {
|
private BroadcastReceiver bondingBroadcastReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(final Context context, final Intent intent) {
|
public void onReceive(final Context context, final Intent intent) {
|
||||||
final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
|
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);
|
final int previousBondState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, -1);
|
||||||
|
|
||||||
// Skip other devices
|
// Skip other devices
|
||||||
if (mBluetoothGatt == null || !device.getAddress().equals(mBluetoothGatt.getDevice().getAddress()))
|
if (bluetoothGatt == null || !device.getAddress().equals(bluetoothGatt.getDevice().getAddress()))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
DebugLogger.i(TAG, "Bond state changed for: " + device.getName() + " new state: " + bondState + " previous: " + previousBondState);
|
DebugLogger.i(TAG, "Bond state changed for: " + device.getName() + " new state: " + bondState + " previous: " + previousBondState);
|
||||||
|
|
||||||
switch (bondState) {
|
switch (bondState) {
|
||||||
case BluetoothDevice.BOND_BONDING:
|
case BluetoothDevice.BOND_BONDING:
|
||||||
mCallbacks.onBondingRequired(device);
|
callbacks.onBondingRequired(device);
|
||||||
break;
|
break;
|
||||||
case BluetoothDevice.BOND_BONDED:
|
case BluetoothDevice.BOND_BONDED:
|
||||||
mCallbacks.onBonded(device);
|
callbacks.onBonded(device);
|
||||||
|
|
||||||
// Start initializing again.
|
// 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.
|
// 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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public BleManager(final Context context, final BleManagerCallbacks callbacks) {
|
public BleManager(final Context context, final BleManagerCallbacks callbacks) {
|
||||||
mCallbacks = callbacks;
|
this.callbacks = callbacks;
|
||||||
mContext = context;
|
this.context = context;
|
||||||
mHandler = new Handler();
|
this.handler = new Handler();
|
||||||
|
|
||||||
// Register bonding broadcast receiver
|
// 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.
|
* 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() {
|
public BleProfile getProfile() {
|
||||||
return mProfile;
|
return profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -176,7 +176,7 @@ public class BleManager implements BleProfileApi {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Context getContext() {
|
public Context getContext() {
|
||||||
return mContext;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -207,11 +207,11 @@ public class BleManager implements BleProfileApi {
|
|||||||
* @param device a device to connect to
|
* @param device a device to connect to
|
||||||
*/
|
*/
|
||||||
public void connect(final BluetoothDevice device) {
|
public void connect(final BluetoothDevice device) {
|
||||||
if (mConnected)
|
if (connected)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
synchronized (mLock) {
|
synchronized (lock) {
|
||||||
if (mBluetoothGatt != null) {
|
if (bluetoothGatt != null) {
|
||||||
// There are 2 ways of reconnecting to the same device:
|
// 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
|
// 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.
|
// 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
|
// device.connectGatt(...) can't be called immediately or service discovery
|
||||||
// may never finish on some older devices (Nexus 4, Android 5.0.1).
|
// 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 shouldAutoConnect() method returned false we can't call gatt.connect() and have to close gatt and open it again.
|
||||||
if (!mInitialConnection) {
|
if (!initialConnection) {
|
||||||
mBluetoothGatt.close();
|
bluetoothGatt.close();
|
||||||
mBluetoothGatt = null;
|
bluetoothGatt = null;
|
||||||
try {
|
try {
|
||||||
Thread.sleep(200); // Is 200 ms enough?
|
Thread.sleep(200); // Is 200 ms enough?
|
||||||
} catch (final InterruptedException e) {
|
} catch (final InterruptedException e) {
|
||||||
@@ -230,29 +230,29 @@ public class BleManager implements BleProfileApi {
|
|||||||
} else {
|
} else {
|
||||||
// Instead, the gatt.connect() method will be used to reconnect to the same device.
|
// 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.
|
// This method forces autoConnect = true even if the gatt was created with this flag set to false.
|
||||||
mInitialConnection = false;
|
initialConnection = false;
|
||||||
mConnectionState = BluetoothGatt.STATE_CONNECTING;
|
connectionState = BluetoothGatt.STATE_CONNECTING;
|
||||||
mCallbacks.onDeviceConnecting(device);
|
callbacks.onDeviceConnecting(device);
|
||||||
mBluetoothGatt.connect();
|
bluetoothGatt.connect();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Register bonding broadcast receiver
|
// Register bonding broadcast receiver
|
||||||
mContext.registerReceiver(mBluetoothStateBroadcastReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
|
context.registerReceiver(bluetoothStateBroadcastReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
|
||||||
mContext.registerReceiver(mBondingBroadcastReceiver, new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED));
|
context.registerReceiver(bondingBroadcastReceiver, new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final boolean shouldAutoConnect = shouldAutoConnect();
|
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.
|
// 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 the shouldAutoConnect() method returned true, the manager will automatically try to reconnect to this device on link loss.
|
||||||
if (shouldAutoConnect)
|
if (shouldAutoConnect)
|
||||||
mInitialConnection = true;
|
initialConnection = true;
|
||||||
mBluetoothDevice = device;
|
bluetoothDevice = device;
|
||||||
mConnectionState = BluetoothGatt.STATE_CONNECTING;
|
connectionState = BluetoothGatt.STATE_CONNECTING;
|
||||||
mCallbacks.onDeviceConnecting(device);
|
callbacks.onDeviceConnecting(device);
|
||||||
mBluetoothGatt = device.connectGatt(mContext, false, mGattCallback = new BleManagerGattCallback());
|
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.
|
* @return true if device is to be disconnected. False if it was already disconnected.
|
||||||
*/
|
*/
|
||||||
public boolean disconnect() {
|
public boolean disconnect() {
|
||||||
mUserDisconnected = true;
|
userDisconnected = true;
|
||||||
mInitialConnection = false;
|
initialConnection = false;
|
||||||
|
|
||||||
if (mBluetoothGatt != null) {
|
if (bluetoothGatt != null) {
|
||||||
mConnectionState = BluetoothGatt.STATE_DISCONNECTING;
|
connectionState = BluetoothGatt.STATE_DISCONNECTING;
|
||||||
mCallbacks.onDeviceDisconnecting(mBluetoothGatt.getDevice());
|
callbacks.onDeviceDisconnecting(bluetoothGatt.getDevice());
|
||||||
final boolean wasConnected = mConnected;
|
final boolean wasConnected = connected;
|
||||||
mBluetoothGatt.disconnect();
|
bluetoothGatt.disconnect();
|
||||||
|
|
||||||
if (!wasConnected) {
|
if (!wasConnected) {
|
||||||
// There will be no callback, the connection attempt will be stopped
|
// There will be no callback, the connection attempt will be stopped
|
||||||
mConnectionState = BluetoothGatt.STATE_DISCONNECTED;
|
connectionState = BluetoothGatt.STATE_DISCONNECTED;
|
||||||
mCallbacks.onDeviceDisconnected(mBluetoothGatt.getDevice());
|
callbacks.onDeviceDisconnected(bluetoothGatt.getDevice());
|
||||||
}
|
}
|
||||||
return true;
|
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.
|
* This method returns true if the device is connected. Services could have not been discovered yet.
|
||||||
*/
|
*/
|
||||||
public boolean isConnected() {
|
public boolean isConnected() {
|
||||||
return mConnected;
|
return connected;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -295,7 +295,7 @@ public class BleManager implements BleProfileApi {
|
|||||||
* @return the connection state
|
* @return the connection state
|
||||||
*/
|
*/
|
||||||
public int getConnectionState() {
|
public int getConnectionState() {
|
||||||
return mConnectionState;
|
return connectionState;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -303,7 +303,7 @@ public class BleManager implements BleProfileApi {
|
|||||||
* @return the last battery level value in percent
|
* @return the last battery level value in percent
|
||||||
*/
|
*/
|
||||||
public int getBatteryValue() {
|
public int getBatteryValue() {
|
||||||
return mBatteryValue;
|
return batteryValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -311,21 +311,21 @@ public class BleManager implements BleProfileApi {
|
|||||||
*/
|
*/
|
||||||
public void close() {
|
public void close() {
|
||||||
try {
|
try {
|
||||||
mContext.unregisterReceiver(mBluetoothStateBroadcastReceiver);
|
context.unregisterReceiver(bluetoothStateBroadcastReceiver);
|
||||||
mContext.unregisterReceiver(mBondingBroadcastReceiver);
|
context.unregisterReceiver(bondingBroadcastReceiver);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// the receiver must have been not registered or unregistered before
|
// the receiver must have been not registered or unregistered before
|
||||||
}
|
}
|
||||||
synchronized (mLock) {
|
synchronized (lock) {
|
||||||
if (mBluetoothGatt != null) {
|
if (bluetoothGatt != null) {
|
||||||
mBluetoothGatt.close();
|
bluetoothGatt.close();
|
||||||
mBluetoothGatt = null;
|
bluetoothGatt = null;
|
||||||
}
|
}
|
||||||
mConnected = false;
|
connected = false;
|
||||||
mInitialConnection = false;
|
initialConnection = false;
|
||||||
mConnectionState = BluetoothGatt.STATE_DISCONNECTED;
|
connectionState = BluetoothGatt.STATE_DISCONNECTED;
|
||||||
mGattCallback = null;
|
gattCallback = null;
|
||||||
mBluetoothDevice = 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.
|
* @return true if pairing has started, false if it was already paired or an immediate error occur.
|
||||||
*/
|
*/
|
||||||
private boolean internalCreateBond() {
|
private boolean internalCreateBond() {
|
||||||
final BluetoothDevice device = mBluetoothDevice;
|
final BluetoothDevice device = bluetoothDevice;
|
||||||
if (device == null)
|
if (device == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -359,7 +359,7 @@ public class BleManager implements BleProfileApi {
|
|||||||
* the Service Changed characteristic or this characteristic does not have the CCCD.
|
* the Service Changed characteristic or this characteristic does not have the CCCD.
|
||||||
*/
|
*/
|
||||||
private boolean ensureServiceChangedEnabled() {
|
private boolean ensureServiceChangedEnabled() {
|
||||||
final BluetoothGatt gatt = mBluetoothGatt;
|
final BluetoothGatt gatt = bluetoothGatt;
|
||||||
if (gatt == null)
|
if (gatt == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -385,7 +385,7 @@ public class BleManager implements BleProfileApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean internalEnableNotifications(final BluetoothGattCharacteristic characteristic) {
|
private boolean internalEnableNotifications(final BluetoothGattCharacteristic characteristic) {
|
||||||
final BluetoothGatt gatt = mBluetoothGatt;
|
final BluetoothGatt gatt = bluetoothGatt;
|
||||||
if (gatt == null || characteristic == null)
|
if (gatt == null || characteristic == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -409,7 +409,7 @@ public class BleManager implements BleProfileApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean internalEnableIndications(final BluetoothGattCharacteristic characteristic) {
|
private boolean internalEnableIndications(final BluetoothGattCharacteristic characteristic) {
|
||||||
final BluetoothGatt gatt = mBluetoothGatt;
|
final BluetoothGatt gatt = bluetoothGatt;
|
||||||
if (gatt == null || characteristic == null)
|
if (gatt == null || characteristic == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -433,7 +433,7 @@ public class BleManager implements BleProfileApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean internalReadCharacteristic(final BluetoothGattCharacteristic characteristic) {
|
private boolean internalReadCharacteristic(final BluetoothGattCharacteristic characteristic) {
|
||||||
final BluetoothGatt gatt = mBluetoothGatt;
|
final BluetoothGatt gatt = bluetoothGatt;
|
||||||
if (gatt == null || characteristic == null)
|
if (gatt == null || characteristic == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -451,7 +451,7 @@ public class BleManager implements BleProfileApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean internalWriteCharacteristic(final BluetoothGattCharacteristic characteristic) {
|
private boolean internalWriteCharacteristic(final BluetoothGattCharacteristic characteristic) {
|
||||||
final BluetoothGatt gatt = mBluetoothGatt;
|
final BluetoothGatt gatt = bluetoothGatt;
|
||||||
if (gatt == null || characteristic == null)
|
if (gatt == null || characteristic == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -469,7 +469,7 @@ public class BleManager implements BleProfileApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean internalReadDescriptor(final BluetoothGattDescriptor descriptor) {
|
private boolean internalReadDescriptor(final BluetoothGattDescriptor descriptor) {
|
||||||
final BluetoothGatt gatt = mBluetoothGatt;
|
final BluetoothGatt gatt = bluetoothGatt;
|
||||||
if (gatt == null || descriptor == null)
|
if (gatt == null || descriptor == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -482,7 +482,7 @@ public class BleManager implements BleProfileApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean internalWriteDescriptor(final BluetoothGattDescriptor descriptor) {
|
private boolean internalWriteDescriptor(final BluetoothGattDescriptor descriptor) {
|
||||||
final BluetoothGatt gatt = mBluetoothGatt;
|
final BluetoothGatt gatt = bluetoothGatt;
|
||||||
if (gatt == null || descriptor == null)
|
if (gatt == null || descriptor == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -495,7 +495,7 @@ public class BleManager implements BleProfileApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean internalReadBatteryLevel() {
|
private boolean internalReadBatteryLevel() {
|
||||||
final BluetoothGatt gatt = mBluetoothGatt;
|
final BluetoothGatt gatt = bluetoothGatt;
|
||||||
if (gatt == null)
|
if (gatt == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -524,7 +524,7 @@ public class BleManager implements BleProfileApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean internalSetBatteryNotifications(final boolean enable) {
|
private boolean internalSetBatteryNotifications(final boolean enable) {
|
||||||
final BluetoothGatt gatt = mBluetoothGatt;
|
final BluetoothGatt gatt = bluetoothGatt;
|
||||||
if (gatt == null) {
|
if (gatt == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -566,7 +566,7 @@ public class BleManager implements BleProfileApi {
|
|||||||
* @return the result of {@link BluetoothGatt#writeDescriptor(BluetoothGattDescriptor)}
|
* @return the result of {@link BluetoothGatt#writeDescriptor(BluetoothGattDescriptor)}
|
||||||
*/
|
*/
|
||||||
private boolean internalWriteDescriptorWorkaround(final BluetoothGattDescriptor descriptor) {
|
private boolean internalWriteDescriptorWorkaround(final BluetoothGattDescriptor descriptor) {
|
||||||
final BluetoothGatt gatt = mBluetoothGatt;
|
final BluetoothGatt gatt = bluetoothGatt;
|
||||||
if (gatt == null || descriptor == null)
|
if (gatt == null || descriptor == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -585,18 +585,19 @@ public class BleManager implements BleProfileApi {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final int getMtu() {
|
public final int getMtu() {
|
||||||
return mMtu;
|
return mtu;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void overrideMtu(final int mtu) {
|
public final void overrideMtu(final int mtu) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
mMtu = mtu;
|
BleManager.this.mtu = mtu;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||||
private boolean internalRequestMtu(final int mtu) {
|
private boolean internalRequestMtu(final int mtu) {
|
||||||
final BluetoothGatt gatt = mBluetoothGatt;
|
final BluetoothGatt gatt = bluetoothGatt;
|
||||||
if (gatt == null)
|
if (gatt == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -605,12 +606,13 @@ public class BleManager implements BleProfileApi {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final boolean requestConnectionPriority(final int priority) {
|
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)
|
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||||
private boolean internalRequestConnectionPriority(final int priority) {
|
private boolean internalRequestConnectionPriority(final int priority) {
|
||||||
final BluetoothGatt gatt = mBluetoothGatt;
|
final BluetoothGatt gatt = bluetoothGatt;
|
||||||
if (gatt == null)
|
if (gatt == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -619,10 +621,10 @@ public class BleManager implements BleProfileApi {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean enqueue(final Request request) {
|
public boolean enqueue(final Request request) {
|
||||||
if (mGattCallback != null) {
|
if (gattCallback != null) {
|
||||||
// Add the new task to the end of the queue
|
// Add the new task to the end of the queue
|
||||||
mGattCallback.mTaskQueue.add(request);
|
gattCallback.taskQueue.add(request);
|
||||||
mGattCallback.nextRequest();
|
gattCallback.nextRequest();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
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_MTU_REQUEST = "Error on mtu request";
|
||||||
private final static String ERROR_CONNECTION_PRIORITY_REQUEST = "Error on connection priority request";
|
private final static String ERROR_CONNECTION_PRIORITY_REQUEST = "Error on connection priority request";
|
||||||
|
|
||||||
private final Queue<Request> mTaskQueue = new LinkedList<>();
|
private final Queue<Request> taskQueue = new LinkedList<>();
|
||||||
private Deque<Request> mInitQueue;
|
private Deque<Request> initQueue;
|
||||||
private boolean mInitInProgress;
|
private boolean initInProgress;
|
||||||
private boolean mOperationInProgress = true;
|
private boolean operationInProgress = true;
|
||||||
/**
|
/**
|
||||||
* This flag is required to resume operations after the connection priority request was made.
|
* 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.
|
* 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
|
* when such request wasn't made, this flag ensures the nextRequest() method won't be called
|
||||||
* during another operation.
|
* during another operation.
|
||||||
*/
|
*/
|
||||||
private boolean mConnectionPriorityOperationInProgress = false;
|
private boolean connectionPriorityOperationInProgress = false;
|
||||||
|
|
||||||
private void notifyDeviceDisconnected(final BluetoothDevice device) {
|
private void notifyDeviceDisconnected(final BluetoothDevice device) {
|
||||||
mConnected = false;
|
connected = false;
|
||||||
mConnectionState = BluetoothGatt.STATE_DISCONNECTED;
|
connectionState = BluetoothGatt.STATE_DISCONNECTED;
|
||||||
if (mUserDisconnected) {
|
if (userDisconnected) {
|
||||||
mCallbacks.onDeviceDisconnected(device);
|
callbacks.onDeviceDisconnected(device);
|
||||||
close();
|
close();
|
||||||
} else {
|
} else {
|
||||||
mCallbacks.onLinklossOccurred(device);
|
callbacks.onLinklossOccurred(device);
|
||||||
// We are not closing the connection here as the device should try to reconnect automatically.
|
// 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.
|
// This may be only called when the shouldAutoConnect() method returned true.
|
||||||
}
|
}
|
||||||
if (mProfile != null)
|
if (profile != null)
|
||||||
mProfile.release();
|
profile.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onError(final BluetoothDevice device, final String message, final int errorCode) {
|
private void onError(final BluetoothDevice device, final String message, final int errorCode) {
|
||||||
mCallbacks.onError(device, message, errorCode);
|
callbacks.onError(device, message, errorCode);
|
||||||
if (mProfile != null)
|
if (profile != null)
|
||||||
mProfile.onError(message, errorCode);
|
profile.onError(message, errorCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void onConnectionStateChange(final BluetoothGatt gatt, final int status, final int newState) {
|
public final void onConnectionStateChange(final BluetoothGatt gatt, final int status, final int newState) {
|
||||||
if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED) {
|
if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED) {
|
||||||
// Notify the parent activity/service
|
// Notify the parent activity/service
|
||||||
mConnected = true;
|
connected = true;
|
||||||
mConnectionState = BluetoothGatt.STATE_CONNECTED;
|
connectionState = BluetoothGatt.STATE_CONNECTED;
|
||||||
mCallbacks.onDeviceConnected(gatt.getDevice());
|
callbacks.onDeviceConnected(gatt.getDevice());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The onConnectionStateChange event is triggered just after the Android connects to a device.
|
* 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 boolean bonded = gatt.getDevice().getBondState() == BluetoothDevice.BOND_BONDED;
|
||||||
final int delay = bonded ? 1600 : 0; // around 1600 ms is required when connection interval is ~45ms.
|
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.
|
// Some proximity tags (e.g. nRF PROXIMITY) initialize bonding automatically when connected.
|
||||||
if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_BONDING) {
|
if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_BONDING) {
|
||||||
gatt.discoverServices();
|
gatt.discoverServices();
|
||||||
@@ -707,16 +709,16 @@ public class BleManager implements BleProfileApi {
|
|||||||
}, delay);
|
}, delay);
|
||||||
} else {
|
} else {
|
||||||
if (newState == BluetoothProfile.STATE_DISCONNECTED) {
|
if (newState == BluetoothProfile.STATE_DISCONNECTED) {
|
||||||
mOperationInProgress = true; // no more calls are possible
|
operationInProgress = true; // no more calls are possible
|
||||||
mInitQueue = null;
|
initQueue = null;
|
||||||
mTaskQueue.clear();
|
taskQueue.clear();
|
||||||
final boolean wasConnected = mConnected;
|
final boolean wasConnected = connected;
|
||||||
// if (mConnected) { // Checking mConnected prevents from calling onDeviceDisconnected if connection attempt failed. This check is not necessary
|
// if (connected) { // Checking connected prevents from calling onDeviceDisconnected if connection attempt failed. This check is not necessary
|
||||||
notifyDeviceDisconnected(gatt.getDevice()); // This sets the mConnected flag to false
|
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.
|
// 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)
|
// This time it will set the autoConnect flag to true (gatt.connect() forces autoConnect true)
|
||||||
if (mInitialConnection) {
|
if (initialConnection) {
|
||||||
connect(gatt.getDevice());
|
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?
|
// 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);
|
final BleProfile profile = BleProfileProvider.findProfile(gatt);
|
||||||
if (profile != null) {
|
if (profile != null) {
|
||||||
profile.setApi(BleManager.this);
|
profile.setApi(BleManager.this);
|
||||||
mProfile = profile;
|
BleManager.this.profile = profile;
|
||||||
|
|
||||||
// Obtain the queue of initialization requests
|
// Obtain the queue of initialization requests
|
||||||
mInitInProgress = true;
|
initInProgress = true;
|
||||||
mInitQueue = profile.initGatt(gatt);
|
initQueue = profile.initGatt(gatt);
|
||||||
|
|
||||||
// Before we start executing the initialization queue some other tasks need to be done.
|
// Before we start executing the initialization queue some other tasks need to be done.
|
||||||
if (mInitQueue == null)
|
if (initQueue == null)
|
||||||
mInitQueue = new LinkedList<>();
|
initQueue = new LinkedList<>();
|
||||||
|
|
||||||
// Note, that operations are added in reverse order to the front of the queue.
|
// 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)
|
// 3. Enable Battery Level notifications if required (if this char. does not exist, this operation will be skipped)
|
||||||
if (mCallbacks.shouldEnableBatteryLevelNotifications(gatt.getDevice()))
|
if (callbacks.shouldEnableBatteryLevelNotifications(gatt.getDevice()))
|
||||||
mInitQueue.addFirst(Request.newEnableBatteryLevelNotificationsRequest());
|
initQueue.addFirst(Request.newEnableBatteryLevelNotificationsRequest());
|
||||||
// 2. Read Battery Level characteristic (if such does not exist, this will be skipped)
|
// 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)
|
// 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)
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N)
|
||||||
mInitQueue.addFirst(Request.newEnableServiceChangedIndicationsRequest());
|
initQueue.addFirst(Request.newEnableServiceChangedIndicationsRequest());
|
||||||
|
|
||||||
mOperationInProgress = false;
|
operationInProgress = false;
|
||||||
nextRequest();
|
nextRequest();
|
||||||
} else {
|
} else {
|
||||||
mCallbacks.onDeviceNotSupported(gatt.getDevice());
|
callbacks.onDeviceNotSupported(gatt.getDevice());
|
||||||
disconnect();
|
disconnect();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -773,13 +775,13 @@ public class BleManager implements BleProfileApi {
|
|||||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||||
if (isBatteryLevelCharacteristic(characteristic)) {
|
if (isBatteryLevelCharacteristic(characteristic)) {
|
||||||
final int batteryValue = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0);
|
final int batteryValue = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0);
|
||||||
mBatteryValue = batteryValue;
|
BleManager.this.batteryValue = batteryValue;
|
||||||
mProfile.onBatteryValueReceived(gatt, batteryValue);
|
profile.onBatteryValueReceived(gatt, batteryValue);
|
||||||
} else {
|
} else {
|
||||||
// The value has been read. Notify the profile and proceed with the initialization queue.
|
// 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();
|
nextRequest();
|
||||||
} else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
|
} else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
|
||||||
if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_NONE) {
|
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) {
|
public final void onCharacteristicWrite(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic, final int status) {
|
||||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||||
// The value has been written. Notify the profile and proceed with the initialization queue.
|
// The value has been written. Notify the profile and proceed with the initialization queue.
|
||||||
mProfile.onCharacteristicWrite(gatt, characteristic);
|
profile.onCharacteristicWrite(gatt, characteristic);
|
||||||
mOperationInProgress = false;
|
operationInProgress = false;
|
||||||
nextRequest();
|
nextRequest();
|
||||||
} else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
|
} else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
|
||||||
if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_NONE) {
|
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) {
|
public void onDescriptorRead(final BluetoothGatt gatt, final BluetoothGattDescriptor descriptor, final int status) {
|
||||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||||
// The value has been read. Notify the profile and proceed with the initialization queue.
|
// The value has been read. Notify the profile and proceed with the initialization queue.
|
||||||
mProfile.onDescriptorRead(gatt, descriptor);
|
profile.onDescriptorRead(gatt, descriptor);
|
||||||
mOperationInProgress = false;
|
operationInProgress = false;
|
||||||
nextRequest();
|
nextRequest();
|
||||||
} else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
|
} else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
|
||||||
if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_NONE) {
|
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) {
|
public final void onDescriptorWrite(final BluetoothGatt gatt, final BluetoothGattDescriptor descriptor, final int status) {
|
||||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||||
// The value has been written. Notify the profile and proceed with the initialization queue.
|
// The value has been written. Notify the profile and proceed with the initialization queue.
|
||||||
mProfile.onDescriptorWrite(gatt, descriptor);
|
profile.onDescriptorWrite(gatt, descriptor);
|
||||||
mOperationInProgress = false;
|
operationInProgress = false;
|
||||||
nextRequest();
|
nextRequest();
|
||||||
} else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
|
} else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
|
||||||
if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_NONE) {
|
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) {
|
public final void onCharacteristicChanged(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
|
||||||
if (isBatteryLevelCharacteristic(characteristic)) {
|
if (isBatteryLevelCharacteristic(characteristic)) {
|
||||||
final int batteryValue = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0);
|
final int batteryValue = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0);
|
||||||
mBatteryValue = batteryValue;
|
BleManager.this.batteryValue = batteryValue;
|
||||||
mProfile.onBatteryValueReceived(gatt, batteryValue);
|
profile.onBatteryValueReceived(gatt, batteryValue);
|
||||||
} else {
|
} else {
|
||||||
final BluetoothGattDescriptor cccd = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID);
|
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;
|
final boolean notifications = cccd == null || cccd.getValue() == null || cccd.getValue().length != 2 || cccd.getValue()[0] == 0x01;
|
||||||
|
|
||||||
if (notifications) {
|
if (notifications) {
|
||||||
mProfile.onCharacteristicNotified(gatt, characteristic);
|
profile.onCharacteristicNotified(gatt, characteristic);
|
||||||
} else { // indications
|
} else { // indications
|
||||||
mProfile.onCharacteristicIndicated(gatt, characteristic);
|
profile.onCharacteristicIndicated(gatt, characteristic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -871,12 +873,12 @@ public class BleManager implements BleProfileApi {
|
|||||||
@Override
|
@Override
|
||||||
public void onMtuChanged(final BluetoothGatt gatt, final int mtu, final int status) {
|
public void onMtuChanged(final BluetoothGatt gatt, final int mtu, final int status) {
|
||||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||||
mProfile.onMtuChanged(mtu);
|
profile.onMtuChanged(mtu);
|
||||||
} else {
|
} else {
|
||||||
DebugLogger.e(TAG, "onMtuChanged error: " + status + ", mtu: " + mtu);
|
DebugLogger.e(TAG, "onMtuChanged error: " + status + ", mtu: " + mtu);
|
||||||
onError(gatt.getDevice(), ERROR_MTU_REQUEST, status);
|
onError(gatt.getDevice(), ERROR_MTU_REQUEST, status);
|
||||||
}
|
}
|
||||||
mOperationInProgress = false;
|
operationInProgress = false;
|
||||||
nextRequest();
|
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) {
|
public void onConnectionUpdated(final BluetoothGatt gatt, final int interval, final int latency, final int timeout, final int status) {
|
||||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||||
mProfile.onConnectionUpdated(interval, latency, timeout);
|
profile.onConnectionUpdated(interval, latency, timeout);
|
||||||
} else if (status == 0x3b) { // HCI_ERR_UNACCEPT_CONN_INTERVAL
|
} else if (status == 0x3b) { // HCI_ERR_UNACCEPT_CONN_INTERVAL
|
||||||
DebugLogger.e(TAG, "onConnectionUpdated received status: Unacceptable connection interval, interval: " + interval + ", latency: " + latency + ", timeout: " + timeout);
|
DebugLogger.e(TAG, "onConnectionUpdated received status: Unacceptable connection interval, interval: " + interval + ", latency: " + latency + ", timeout: " + timeout);
|
||||||
} else {
|
} else {
|
||||||
DebugLogger.e(TAG, "onConnectionUpdated received status: " + status + ", interval: " + interval + ", latency: " + latency + ", timeout: " + timeout);
|
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) {
|
if (connectionPriorityOperationInProgress) {
|
||||||
mConnectionPriorityOperationInProgress = false;
|
connectionPriorityOperationInProgress = false;
|
||||||
mOperationInProgress = false;
|
operationInProgress = false;
|
||||||
nextRequest();
|
nextRequest();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -915,28 +917,28 @@ public class BleManager implements BleProfileApi {
|
|||||||
* the {@link BleManagerCallbacks#onDeviceReady(BluetoothDevice)} callback is called.
|
* the {@link BleManagerCallbacks#onDeviceReady(BluetoothDevice)} callback is called.
|
||||||
*/
|
*/
|
||||||
private void nextRequest() {
|
private void nextRequest() {
|
||||||
if (mOperationInProgress)
|
if (operationInProgress)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Get the first request from the init queue
|
// 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?
|
// Are we done with initializing?
|
||||||
if (request == null) {
|
if (request == null) {
|
||||||
if (mInitInProgress) {
|
if (initInProgress) {
|
||||||
mInitQueue = null; // release the queue
|
initQueue = null; // release the queue
|
||||||
mInitInProgress = false;
|
initInProgress = false;
|
||||||
mCallbacks.onDeviceReady(mBluetoothDevice);
|
callbacks.onDeviceReady(bluetoothDevice);
|
||||||
}
|
}
|
||||||
// If so, we can continue with the task queue
|
// If so, we can continue with the task queue
|
||||||
request = mTaskQueue.poll();
|
request = taskQueue.poll();
|
||||||
if (request == null) {
|
if (request == null) {
|
||||||
// Nothing to be done for now
|
// Nothing to be done for now
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mOperationInProgress = true;
|
operationInProgress = true;
|
||||||
boolean result = false;
|
boolean result = false;
|
||||||
switch (request.type) {
|
switch (request.type) {
|
||||||
case CREATE_BOND: {
|
case CREATE_BOND: {
|
||||||
@@ -994,15 +996,15 @@ public class BleManager implements BleProfileApi {
|
|||||||
}
|
}
|
||||||
case REQUEST_CONNECTION_PRIORITY: {
|
case REQUEST_CONNECTION_PRIORITY: {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
mConnectionPriorityOperationInProgress = true;
|
connectionPriorityOperationInProgress = true;
|
||||||
result = internalRequestConnectionPriority(request.value);
|
result = internalRequestConnectionPriority(request.value);
|
||||||
} else {
|
} else {
|
||||||
result = internalRequestConnectionPriority(request.value);
|
result = internalRequestConnectionPriority(request.value);
|
||||||
// There is no callback for requestConnectionPriority(...) before Android Oreo.\
|
// There is no callback for requestConnectionPriority(...) before Android Oreo.\
|
||||||
// Let's give it some time to finish as the request is an asynchronous operation.
|
// Let's give it some time to finish as the request is an asynchronous operation.
|
||||||
if (result) {
|
if (result) {
|
||||||
mHandler.postDelayed(() -> {
|
handler.postDelayed(() -> {
|
||||||
mOperationInProgress = false;
|
operationInProgress = false;
|
||||||
nextRequest();
|
nextRequest();
|
||||||
}, 100);
|
}, 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.
|
// 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.
|
// In that case, proceed with next operation and ignore the one that failed.
|
||||||
if (!result) {
|
if (!result) {
|
||||||
mConnectionPriorityOperationInProgress = false;
|
connectionPriorityOperationInProgress = false;
|
||||||
mOperationInProgress = false;
|
operationInProgress = false;
|
||||||
nextRequest();
|
nextRequest();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,19 +32,19 @@ import android.os.Build;
|
|||||||
import java.util.Deque;
|
import java.util.Deque;
|
||||||
|
|
||||||
public abstract class BleProfile {
|
public abstract class BleProfile {
|
||||||
private Context mContext;
|
private Context context;
|
||||||
private BleProfileApi mApi;
|
private BleProfileApi api;
|
||||||
|
|
||||||
/* package */ void setApi(final BleProfileApi api) {
|
/* package */ void setApi(final BleProfileApi api) {
|
||||||
this.mContext = api.getContext();
|
this.context = api.getContext();
|
||||||
this.mApi = api;
|
this.api = api;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the BLE API for sending data to the remote device.
|
* Returns the BLE API for sending data to the remote device.
|
||||||
*/
|
*/
|
||||||
public BleProfileApi getApi() {
|
public BleProfileApi getApi() {
|
||||||
return mApi;
|
return api;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -52,7 +52,7 @@ public abstract class BleProfile {
|
|||||||
* @return the context
|
* @return the context
|
||||||
*/
|
*/
|
||||||
public Context getContext() {
|
public Context getContext() {
|
||||||
return mContext;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -62,15 +62,15 @@ public class BleProfileService extends Service implements BleManagerCallbacks {
|
|||||||
public static final int STATE_CONNECTING = 2;
|
public static final int STATE_CONNECTING = 2;
|
||||||
public static final int STATE_DISCONNECTING = 3;
|
public static final int STATE_DISCONNECTING = 3;
|
||||||
|
|
||||||
private BleManager mBleManager;
|
private BleManager bleManager;
|
||||||
private Handler mHandler;
|
private Handler handler;
|
||||||
|
|
||||||
protected boolean mBound;
|
protected boolean bound;
|
||||||
private boolean mConnected;
|
private boolean connected;
|
||||||
private BluetoothDevice mBluetoothDevice;
|
private BluetoothDevice bluetoothDevice;
|
||||||
private String mDeviceName;
|
private String deviceName;
|
||||||
|
|
||||||
private final BroadcastReceiver mBluetoothStateBroadcastReceiver = new BroadcastReceiver() {
|
private final BroadcastReceiver bluetoothStateBroadcastReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(final Context context, final Intent intent) {
|
public void onReceive(final Context context, final Intent intent) {
|
||||||
final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF);
|
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.
|
* Disconnects from the sensor.
|
||||||
*/
|
*/
|
||||||
public void disconnect() {
|
public void disconnect() {
|
||||||
if (!mConnected) {
|
if (!connected) {
|
||||||
mBleManager.close();
|
bleManager.close();
|
||||||
onDeviceDisconnected(mBluetoothDevice);
|
onDeviceDisconnected(bluetoothDevice);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mBleManager.disconnect();
|
bleManager.disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -107,7 +107,7 @@ public class BleProfileService extends Service implements BleManagerCallbacks {
|
|||||||
* @return device address
|
* @return device address
|
||||||
*/
|
*/
|
||||||
public final String getDeviceAddress() {
|
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
|
* @return the device name
|
||||||
*/
|
*/
|
||||||
public final String getDeviceName() {
|
public final String getDeviceName() {
|
||||||
return mDeviceName;
|
return deviceName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -125,7 +125,7 @@ public class BleProfileService extends Service implements BleManagerCallbacks {
|
|||||||
* @return the Bluetooth device
|
* @return the Bluetooth device
|
||||||
*/
|
*/
|
||||||
public final BluetoothDevice getBluetoothDevice() {
|
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
|
* @return <code>true</code> if device is connected to the sensor, <code>false</code> otherwise
|
||||||
*/
|
*/
|
||||||
public final boolean isConnected() {
|
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.
|
* 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() {
|
public final BleProfile getProfile() {
|
||||||
return mBleManager.getProfile();
|
return bleManager.getProfile();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,18 +157,18 @@ public class BleProfileService extends Service implements BleManagerCallbacks {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBinder onBind(final Intent intent) {
|
public IBinder onBind(final Intent intent) {
|
||||||
mBound = true;
|
bound = true;
|
||||||
return getBinder();
|
return getBinder();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void onRebind(final Intent intent) {
|
public final void onRebind(final Intent intent) {
|
||||||
mBound = true;
|
bound = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final boolean onUnbind(final Intent intent) {
|
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
|
// We want the onRebind method be called if anything else binds to it again
|
||||||
return true;
|
return true;
|
||||||
@@ -179,13 +179,13 @@ public class BleProfileService extends Service implements BleManagerCallbacks {
|
|||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
|
|
||||||
mHandler = new Handler();
|
handler = new Handler();
|
||||||
|
|
||||||
// initialize the manager
|
// initialize the manager
|
||||||
mBleManager = new BleManager(this, this);
|
bleManager = new BleManager(this, this);
|
||||||
|
|
||||||
// Register broadcast receivers
|
// Register broadcast receivers
|
||||||
registerReceiver(mBluetoothStateBroadcastReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
|
registerReceiver(bluetoothStateBroadcastReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
|
||||||
|
|
||||||
// Service has now been created
|
// Service has now been created
|
||||||
onServiceCreated();
|
onServiceCreated();
|
||||||
@@ -209,15 +209,15 @@ public class BleProfileService extends Service implements BleManagerCallbacks {
|
|||||||
if (intent == null || !intent.hasExtra(EXTRA_DEVICE_ADDRESS))
|
if (intent == null || !intent.hasExtra(EXTRA_DEVICE_ADDRESS))
|
||||||
throw new UnsupportedOperationException("No device address at EXTRA_DEVICE_ADDRESS key");
|
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 BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
|
||||||
final BluetoothAdapter adapter = bluetoothManager.getAdapter();
|
final BluetoothAdapter adapter = bluetoothManager.getAdapter();
|
||||||
final String deviceAddress = intent.getStringExtra(EXTRA_DEVICE_ADDRESS);
|
final String deviceAddress = intent.getStringExtra(EXTRA_DEVICE_ADDRESS);
|
||||||
mBluetoothDevice = adapter.getRemoteDevice(deviceAddress);
|
bluetoothDevice = adapter.getRemoteDevice(deviceAddress);
|
||||||
onServiceStarted();
|
onServiceStarted();
|
||||||
|
|
||||||
mBleManager.connect(mBluetoothDevice);
|
bleManager.connect(bluetoothDevice);
|
||||||
return START_REDELIVER_INTENT;
|
return START_REDELIVER_INTENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,14 +232,14 @@ public class BleProfileService extends Service implements BleManagerCallbacks {
|
|||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
// Unregister broadcast receivers
|
// Unregister broadcast receivers
|
||||||
unregisterReceiver(mBluetoothStateBroadcastReceiver);
|
unregisterReceiver(bluetoothStateBroadcastReceiver);
|
||||||
|
|
||||||
// shutdown the manager
|
// shutdown the manager
|
||||||
mBleManager.close();
|
bleManager.close();
|
||||||
mBleManager = null;
|
bleManager = null;
|
||||||
mBluetoothDevice = null;
|
bluetoothDevice = null;
|
||||||
mDeviceName = null;
|
deviceName = null;
|
||||||
mConnected = false;
|
connected = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -261,25 +261,25 @@ public class BleProfileService extends Service implements BleManagerCallbacks {
|
|||||||
@Override
|
@Override
|
||||||
public boolean shouldEnableBatteryLevelNotifications(final BluetoothDevice device) {
|
public boolean shouldEnableBatteryLevelNotifications(final BluetoothDevice device) {
|
||||||
// By default the Battery Level notifications will be enabled only the activity is bound.
|
// By default the Battery Level notifications will be enabled only the activity is bound.
|
||||||
return mBound;
|
return bound;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceConnecting(final BluetoothDevice device) {
|
public void onDeviceConnecting(final BluetoothDevice device) {
|
||||||
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
|
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);
|
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_CONNECTING);
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceConnected(final BluetoothDevice device) {
|
public void onDeviceConnected(final BluetoothDevice device) {
|
||||||
mConnected = true;
|
connected = true;
|
||||||
|
|
||||||
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
|
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
|
||||||
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_CONNECTED);
|
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_CONNECTED);
|
||||||
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
|
broadcast.putExtra(EXTRA_DEVICE, bluetoothDevice);
|
||||||
broadcast.putExtra(EXTRA_DEVICE_NAME, mDeviceName);
|
broadcast.putExtra(EXTRA_DEVICE_NAME, deviceName);
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,14 +287,14 @@ public class BleProfileService extends Service implements BleManagerCallbacks {
|
|||||||
public void onDeviceDisconnecting(final BluetoothDevice device) {
|
public void onDeviceDisconnecting(final BluetoothDevice device) {
|
||||||
// Notify user about changing the state to DISCONNECTING
|
// Notify user about changing the state to DISCONNECTING
|
||||||
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
|
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);
|
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_DISCONNECTING);
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceDisconnected(final BluetoothDevice device) {
|
public void onDeviceDisconnected(final BluetoothDevice device) {
|
||||||
mConnected = false;
|
connected = false;
|
||||||
|
|
||||||
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
|
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
|
||||||
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_DISCONNECTED);
|
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_DISCONNECTED);
|
||||||
@@ -305,10 +305,10 @@ public class BleProfileService extends Service implements BleManagerCallbacks {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLinklossOccurred(final BluetoothDevice device) {
|
public void onLinklossOccurred(final BluetoothDevice device) {
|
||||||
mConnected = false;
|
connected = false;
|
||||||
|
|
||||||
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
|
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);
|
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_LINK_LOSS);
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||||
}
|
}
|
||||||
@@ -316,14 +316,14 @@ public class BleProfileService extends Service implements BleManagerCallbacks {
|
|||||||
@Override
|
@Override
|
||||||
public void onDeviceReady(final BluetoothDevice device) {
|
public void onDeviceReady(final BluetoothDevice device) {
|
||||||
final Intent broadcast = new Intent(BROADCAST_DEVICE_READY);
|
final Intent broadcast = new Intent(BROADCAST_DEVICE_READY);
|
||||||
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
|
broadcast.putExtra(EXTRA_DEVICE, bluetoothDevice);
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceNotSupported(final BluetoothDevice device) {
|
public void onDeviceNotSupported(final BluetoothDevice device) {
|
||||||
final Intent broadcast = new Intent(BROADCAST_DEVICE_NOT_SUPPORTED);
|
final Intent broadcast = new Intent(BROADCAST_DEVICE_NOT_SUPPORTED);
|
||||||
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
|
broadcast.putExtra(EXTRA_DEVICE, bluetoothDevice);
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||||
|
|
||||||
// no need for disconnecting, it will be disconnected by the manager automatically
|
// 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);
|
showToast(no.nordicsemi.android.nrftoolbox.common.R.string.bonding);
|
||||||
|
|
||||||
final Intent broadcast = new Intent(BROADCAST_BOND_STATE);
|
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);
|
broadcast.putExtra(EXTRA_BOND_STATE, BluetoothDevice.BOND_BONDING);
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
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);
|
showToast(no.nordicsemi.android.nrftoolbox.common.R.string.bonded);
|
||||||
|
|
||||||
final Intent broadcast = new Intent(BROADCAST_BOND_STATE);
|
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);
|
broadcast.putExtra(EXTRA_BOND_STATE, BluetoothDevice.BOND_BONDED);
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||||
}
|
}
|
||||||
@@ -352,14 +352,14 @@ public class BleProfileService extends Service implements BleManagerCallbacks {
|
|||||||
@Override
|
@Override
|
||||||
public void onError(final BluetoothDevice device, final String message, final int errorCode) {
|
public void onError(final BluetoothDevice device, final String message, final int errorCode) {
|
||||||
final Intent broadcast = new Intent(BROADCAST_ERROR);
|
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_MESSAGE, message);
|
||||||
broadcast.putExtra(EXTRA_ERROR_CODE, errorCode);
|
broadcast.putExtra(EXTRA_ERROR_CODE, errorCode);
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||||
|
|
||||||
// After receiving an error the device will be automatically disconnected.
|
// After receiving an error the device will be automatically disconnected.
|
||||||
// Replace it with other implementation if necessary.
|
// Replace it with other implementation if necessary.
|
||||||
mBleManager.disconnect();
|
bleManager.disconnect();
|
||||||
stopSelf();
|
stopSelf();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -370,7 +370,7 @@ public class BleProfileService extends Service implements BleManagerCallbacks {
|
|||||||
* an resource id of the message to be shown
|
* an resource id of the message to be shown
|
||||||
*/
|
*/
|
||||||
private void showToast(final int messageResId) {
|
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());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -65,12 +65,12 @@ public class UARTCommandsActivity extends Activity implements UARTCommandsAdapte
|
|||||||
|
|
||||||
public static final String CONFIGURATION = "configuration";
|
public static final String CONFIGURATION = "configuration";
|
||||||
|
|
||||||
private GoogleApiClient mGoogleApiClient;
|
private GoogleApiClient googleApiClient;
|
||||||
private UARTCommandsAdapter mAdapter;
|
private UARTCommandsAdapter adapter;
|
||||||
private UARTProfile mProfile;
|
private UARTProfile profile;
|
||||||
private long mConfigurationId;
|
private long configurationId;
|
||||||
|
|
||||||
private BroadcastReceiver mServiceBroadcastReceiver = new BroadcastReceiver() {
|
private BroadcastReceiver serviceBroadcastReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(final Context context, final Intent intent) {
|
public void onReceive(final Context context, final Intent intent) {
|
||||||
final String action = intent.getAction();
|
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
|
@Override
|
||||||
public void onServiceConnected(final ComponentName name, final IBinder service) {
|
public void onServiceConnected(final ComponentName name, final IBinder service) {
|
||||||
final BleProfileService.LocalBinder binder = (BleProfileService.LocalBinder) service;
|
final BleProfileService.LocalBinder binder = (BleProfileService.LocalBinder) service;
|
||||||
mProfile = (UARTProfile) binder.getProfile();
|
profile = (UARTProfile) binder.getProfile();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onServiceDisconnected(final ComponentName name) {
|
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 Intent intent = getIntent();
|
||||||
final UartConfiguration configuration = intent.getParcelableExtra(CONFIGURATION);
|
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.
|
// 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.
|
// 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);
|
final Intent service = new Intent(this, BleProfileService.class);
|
||||||
bindService(service, mServiceConnection, 0);
|
bindService(service, serviceConnection, 0);
|
||||||
|
|
||||||
// Set up tht grid
|
// Set up tht grid
|
||||||
final GridViewPager pager = findViewById(R.id.pager);
|
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);
|
final DotsPageIndicator dotsPageIndicator = findViewById(R.id.page_indicator);
|
||||||
dotsPageIndicator.setPager(pager);
|
dotsPageIndicator.setPager(pager);
|
||||||
|
|
||||||
// Configure Google API client
|
// Configure Google API client
|
||||||
mGoogleApiClient = new GoogleApiClient.Builder(this)
|
googleApiClient = new GoogleApiClient.Builder(this)
|
||||||
.addApi(Wearable.API)
|
.addApi(Wearable.API)
|
||||||
.addConnectionCallbacks(this)
|
.addConnectionCallbacks(this)
|
||||||
.addOnConnectionFailedListener(this)
|
.addOnConnectionFailedListener(this)
|
||||||
@@ -146,39 +146,39 @@ public class UARTCommandsActivity extends Activity implements UARTCommandsAdapte
|
|||||||
filter.addAction(BleProfileService.BROADCAST_CONNECTION_STATE);
|
filter.addAction(BleProfileService.BROADCAST_CONNECTION_STATE);
|
||||||
filter.addAction(BleProfileService.BROADCAST_ERROR);
|
filter.addAction(BleProfileService.BROADCAST_ERROR);
|
||||||
filter.addAction(UARTProfile.BROADCAST_DATA_RECEIVED);
|
filter.addAction(UARTProfile.BROADCAST_DATA_RECEIVED);
|
||||||
LocalBroadcastManager.getInstance(this).registerReceiver(mServiceBroadcastReceiver, filter);
|
LocalBroadcastManager.getInstance(this).registerReceiver(serviceBroadcastReceiver, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
mGoogleApiClient.unregisterConnectionCallbacks(this);
|
googleApiClient.unregisterConnectionCallbacks(this);
|
||||||
mGoogleApiClient.unregisterConnectionFailedListener(this);
|
googleApiClient.unregisterConnectionFailedListener(this);
|
||||||
mGoogleApiClient = null;
|
googleApiClient = null;
|
||||||
|
|
||||||
// unbind if we were bound to the service.
|
// unbind if we were bound to the service.
|
||||||
unbindService(mServiceConnection);
|
unbindService(serviceConnection);
|
||||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(mServiceBroadcastReceiver);
|
LocalBroadcastManager.getInstance(this).unregisterReceiver(serviceBroadcastReceiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStart() {
|
protected void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
mGoogleApiClient.connect();
|
googleApiClient.connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStop() {
|
protected void onStop() {
|
||||||
super.onStop();
|
super.onStop();
|
||||||
Wearable.MessageApi.removeListener(mGoogleApiClient, this);
|
Wearable.MessageApi.removeListener(googleApiClient, this);
|
||||||
Wearable.DataApi.removeListener(mGoogleApiClient, this);
|
Wearable.DataApi.removeListener(googleApiClient, this);
|
||||||
mGoogleApiClient.disconnect();
|
googleApiClient.disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onConnected(final Bundle bundle) {
|
public void onConnected(final Bundle bundle) {
|
||||||
Wearable.DataApi.addListener(mGoogleApiClient, this);
|
Wearable.DataApi.addListener(googleApiClient, this);
|
||||||
Wearable.MessageApi.addListener(mGoogleApiClient, this);
|
Wearable.MessageApi.addListener(googleApiClient, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -198,7 +198,7 @@ public class UARTCommandsActivity extends Activity implements UARTCommandsAdapte
|
|||||||
final long id = ContentUris.parseId(item.getUri());
|
final long id = ContentUris.parseId(item.getUri());
|
||||||
|
|
||||||
// Update the configuration only if ID matches
|
// Update the configuration only if ID matches
|
||||||
if (id != mConfigurationId)
|
if (id != configurationId)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Configuration added or edited
|
// Configuration added or edited
|
||||||
@@ -207,12 +207,12 @@ public class UARTCommandsActivity extends Activity implements UARTCommandsAdapte
|
|||||||
final UartConfiguration configuration = new UartConfiguration(dataMap, id);
|
final UartConfiguration configuration = new UartConfiguration(dataMap, id);
|
||||||
|
|
||||||
// Update UI on UI thread
|
// Update UI on UI thread
|
||||||
runOnUiThread(() -> mAdapter.setConfiguration(configuration));
|
runOnUiThread(() -> adapter.setConfiguration(configuration));
|
||||||
} else if (event.getType() == DataEvent.TYPE_DELETED) {
|
} else if (event.getType() == DataEvent.TYPE_DELETED) {
|
||||||
// Configuration removed
|
// Configuration removed
|
||||||
|
|
||||||
// Update UI on UI thread
|
// 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
|
@Override
|
||||||
public void onMessageReceived(final MessageEvent messageEvent) {
|
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 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;
|
return;
|
||||||
|
|
||||||
switch (messageEvent.getPath()) {
|
switch (messageEvent.getPath()) {
|
||||||
@@ -246,8 +246,8 @@ public class UARTCommandsActivity extends Activity implements UARTCommandsAdapte
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mProfile != null)
|
if (profile != null)
|
||||||
mProfile.send(text);
|
profile.send(text);
|
||||||
else
|
else
|
||||||
sendMessageToHandheld(this, text);
|
sendMessageToHandheld(this, text);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,21 +34,21 @@ import no.nordicsemi.android.nrftoolbox.uart.domain.Command;
|
|||||||
import no.nordicsemi.android.nrftoolbox.uart.domain.UartConfiguration;
|
import no.nordicsemi.android.nrftoolbox.uart.domain.UartConfiguration;
|
||||||
|
|
||||||
public class UARTCommandsAdapter extends GridPagerAdapter {
|
public class UARTCommandsAdapter extends GridPagerAdapter {
|
||||||
private final OnCommandSelectedListener mListener;
|
private final OnCommandSelectedListener listener;
|
||||||
private UartConfiguration mConfiguration;
|
private UartConfiguration configuration;
|
||||||
|
|
||||||
public interface OnCommandSelectedListener {
|
public interface OnCommandSelectedListener {
|
||||||
void onCommandSelected(final Command command);
|
void onCommandSelected(final Command command);
|
||||||
}
|
}
|
||||||
|
|
||||||
public UARTCommandsAdapter(final UartConfiguration configuration, final OnCommandSelectedListener listener) {
|
public UARTCommandsAdapter(final UartConfiguration configuration, final OnCommandSelectedListener listener) {
|
||||||
this.mConfiguration = configuration;
|
this.configuration = configuration;
|
||||||
this.mListener = listener;
|
this.listener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setConfiguration(final UartConfiguration configuration) {
|
public void setConfiguration(final UartConfiguration configuration) {
|
||||||
// Configuration is null when it has been deleted on the handheld
|
// Configuration is null when it has been deleted on the handheld
|
||||||
this.mConfiguration = configuration;
|
this.configuration = configuration;
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ public class UARTCommandsAdapter extends GridPagerAdapter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getColumnCount(final int row) {
|
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
|
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);
|
final View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.action_item, viewGroup, false);
|
||||||
viewGroup.addView(view);
|
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) {
|
if (commands != null && commands.length > 0) {
|
||||||
final Command command = commands[column];
|
final Command command = commands[column];
|
||||||
|
|
||||||
final CircularButton icon = view.findViewById(R.id.icon);
|
final CircularButton icon = view.findViewById(R.id.icon);
|
||||||
icon.getImageDrawable().setLevel(command.getIconIndex());
|
icon.getImageDrawable().setLevel(command.getIconIndex());
|
||||||
icon.setOnClickListener(v -> mListener.onCommandSelected(command));
|
icon.setOnClickListener(v -> listener.onCommandSelected(command));
|
||||||
} else {
|
} else {
|
||||||
// Hide the icon
|
// Hide the icon
|
||||||
view.findViewById(R.id.icon).setVisibility(View.GONE);
|
view.findViewById(R.id.icon).setVisibility(View.GONE);
|
||||||
|
|||||||
@@ -43,19 +43,19 @@ public class UARTConfigurationItemLayout extends LinearLayout implements Wearabl
|
|||||||
private static final float SHRINK_LABEL_ALPHA = .5f;
|
private static final float SHRINK_LABEL_ALPHA = .5f;
|
||||||
private static final float EXPAND_LABEL_ALPHA = 1f;
|
private static final float EXPAND_LABEL_ALPHA = 1f;
|
||||||
|
|
||||||
private float mExpandCircleRadius;
|
private float expandCircleRadius;
|
||||||
private float mShrinkCircleRadius;
|
private float shrinkCircleRadius;
|
||||||
|
|
||||||
private ObjectAnimator mExpandCircleAnimator;
|
private ObjectAnimator expandCircleAnimator;
|
||||||
private ObjectAnimator mFadeInLabelAnimator;
|
private ObjectAnimator fadeInLabelAnimator;
|
||||||
private AnimatorSet mExpandAnimator;
|
private AnimatorSet expandAnimator;
|
||||||
|
|
||||||
private ObjectAnimator mShrinkCircleAnimator;
|
private ObjectAnimator shrinkCircleAnimator;
|
||||||
private ObjectAnimator mFadeOutLabelAnimator;
|
private ObjectAnimator fadeOutLabelAnimator;
|
||||||
private AnimatorSet mShrinkAnimator;
|
private AnimatorSet shrinkAnimator;
|
||||||
|
|
||||||
private TextView mName;
|
private TextView name;
|
||||||
private CircledImageView mIcon;
|
private CircledImageView icon;
|
||||||
|
|
||||||
public UARTConfigurationItemLayout(final Context context) {
|
public UARTConfigurationItemLayout(final Context context) {
|
||||||
this(context, null, 0);
|
this(context, null, 0);
|
||||||
@@ -73,53 +73,53 @@ public class UARTConfigurationItemLayout extends LinearLayout implements Wearabl
|
|||||||
protected void onFinishInflate() {
|
protected void onFinishInflate() {
|
||||||
super.onFinishInflate();
|
super.onFinishInflate();
|
||||||
|
|
||||||
mName = findViewById(R.id.name);
|
name = findViewById(R.id.name);
|
||||||
mIcon = findViewById(R.id.icon);
|
icon = findViewById(R.id.icon);
|
||||||
mExpandCircleRadius = mIcon.getCircleRadius();
|
expandCircleRadius = icon.getCircleRadius();
|
||||||
mShrinkCircleRadius = mExpandCircleRadius * SHRINK_CIRCLE_RATIO;
|
shrinkCircleRadius = expandCircleRadius * SHRINK_CIRCLE_RATIO;
|
||||||
|
|
||||||
mShrinkCircleAnimator = ObjectAnimator.ofFloat(mIcon, "circleRadius", mExpandCircleRadius, mShrinkCircleRadius);
|
shrinkCircleAnimator = ObjectAnimator.ofFloat(icon, "circleRadius", expandCircleRadius, shrinkCircleRadius);
|
||||||
mFadeOutLabelAnimator = ObjectAnimator.ofFloat(mName, "alpha", EXPAND_LABEL_ALPHA, SHRINK_LABEL_ALPHA);
|
fadeOutLabelAnimator = ObjectAnimator.ofFloat(name, "alpha", EXPAND_LABEL_ALPHA, SHRINK_LABEL_ALPHA);
|
||||||
mShrinkAnimator = new AnimatorSet().setDuration(ANIMATION_DURATION_MS);
|
shrinkAnimator = new AnimatorSet().setDuration(ANIMATION_DURATION_MS);
|
||||||
mShrinkAnimator.playTogether(mShrinkCircleAnimator, mFadeOutLabelAnimator);
|
shrinkAnimator.playTogether(shrinkCircleAnimator, fadeOutLabelAnimator);
|
||||||
|
|
||||||
mExpandCircleAnimator = ObjectAnimator.ofFloat(mIcon, "circleRadius", mShrinkCircleRadius, mExpandCircleRadius);
|
expandCircleAnimator = ObjectAnimator.ofFloat(icon, "circleRadius", shrinkCircleRadius, expandCircleRadius);
|
||||||
mFadeInLabelAnimator = ObjectAnimator.ofFloat(mName, "alpha", SHRINK_LABEL_ALPHA, EXPAND_LABEL_ALPHA);
|
fadeInLabelAnimator = ObjectAnimator.ofFloat(name, "alpha", SHRINK_LABEL_ALPHA, EXPAND_LABEL_ALPHA);
|
||||||
mExpandAnimator = new AnimatorSet().setDuration(ANIMATION_DURATION_MS);
|
expandAnimator = new AnimatorSet().setDuration(ANIMATION_DURATION_MS);
|
||||||
mExpandAnimator.playTogether(mExpandCircleAnimator, mFadeInLabelAnimator);
|
expandAnimator.playTogether(expandCircleAnimator, fadeInLabelAnimator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCenterPosition(final boolean animate) {
|
public void onCenterPosition(final boolean animate) {
|
||||||
if (animate) {
|
if (animate) {
|
||||||
mShrinkAnimator.cancel();
|
shrinkAnimator.cancel();
|
||||||
if (!mExpandAnimator.isRunning()) {
|
if (!expandAnimator.isRunning()) {
|
||||||
mExpandCircleAnimator.setFloatValues(mIcon.getCircleRadius(), mExpandCircleRadius);
|
expandCircleAnimator.setFloatValues(icon.getCircleRadius(), expandCircleRadius);
|
||||||
mFadeInLabelAnimator.setFloatValues(mName.getAlpha(), EXPAND_LABEL_ALPHA);
|
fadeInLabelAnimator.setFloatValues(name.getAlpha(), EXPAND_LABEL_ALPHA);
|
||||||
mExpandAnimator.start();
|
expandAnimator.start();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mExpandAnimator.cancel();
|
expandAnimator.cancel();
|
||||||
mIcon.setCircleRadius(mExpandCircleRadius);
|
icon.setCircleRadius(expandCircleRadius);
|
||||||
mName.setAlpha(EXPAND_LABEL_ALPHA);
|
name.setAlpha(EXPAND_LABEL_ALPHA);
|
||||||
}
|
}
|
||||||
mIcon.setEnabled(true);
|
icon.setEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNonCenterPosition(final boolean animate) {
|
public void onNonCenterPosition(final boolean animate) {
|
||||||
if (animate) {
|
if (animate) {
|
||||||
mExpandAnimator.cancel();
|
expandAnimator.cancel();
|
||||||
if (!mShrinkAnimator.isRunning()) {
|
if (!shrinkAnimator.isRunning()) {
|
||||||
mShrinkCircleAnimator.setFloatValues(mIcon.getCircleRadius(), mShrinkCircleRadius);
|
shrinkCircleAnimator.setFloatValues(icon.getCircleRadius(), shrinkCircleRadius);
|
||||||
mFadeOutLabelAnimator.setFloatValues(mName.getAlpha(), SHRINK_LABEL_ALPHA);
|
fadeOutLabelAnimator.setFloatValues(name.getAlpha(), SHRINK_LABEL_ALPHA);
|
||||||
mShrinkAnimator.start();
|
shrinkAnimator.start();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mShrinkAnimator.cancel();
|
shrinkAnimator.cancel();
|
||||||
mIcon.setCircleRadius(mShrinkCircleRadius);
|
icon.setCircleRadius(shrinkCircleRadius);
|
||||||
mName.setAlpha(SHRINK_LABEL_ALPHA);
|
name.setAlpha(SHRINK_LABEL_ALPHA);
|
||||||
}
|
}
|
||||||
mIcon.setEnabled(false);
|
icon.setEnabled(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,11 +60,11 @@ import no.nordicsemi.android.nrftoolbox.uart.domain.UartConfiguration;
|
|||||||
|
|
||||||
public class UARTConfigurationsActivity extends Activity implements GoogleApiClient.ConnectionCallbacks,
|
public class UARTConfigurationsActivity extends Activity implements GoogleApiClient.ConnectionCallbacks,
|
||||||
DataApi.DataListener, GoogleApiClient.OnConnectionFailedListener, WearableListView.ClickListener, MessageApi.MessageListener {
|
DataApi.DataListener, GoogleApiClient.OnConnectionFailedListener, WearableListView.ClickListener, MessageApi.MessageListener {
|
||||||
private UARTConfigurationsAdapter mAdapter;
|
private UARTConfigurationsAdapter adapter;
|
||||||
private GoogleApiClient mGoogleApiClient;
|
private GoogleApiClient googleApiClient;
|
||||||
private BleProfileService.LocalBinder mBinder;
|
private BleProfileService.LocalBinder binder;
|
||||||
|
|
||||||
private BroadcastReceiver mServiceBroadcastReceiver = new BroadcastReceiver() {
|
private BroadcastReceiver serviceBroadcastReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(final Context context, final Intent intent) {
|
public void onReceive(final Context context, final Intent intent) {
|
||||||
final String action = intent.getAction();
|
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
|
@Override
|
||||||
public void onServiceConnected(final ComponentName name, final IBinder service) {
|
public void onServiceConnected(final ComponentName name, final IBinder service) {
|
||||||
mBinder = (BleProfileService.LocalBinder) service;
|
binder = (BleProfileService.LocalBinder) service;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onServiceDisconnected(final ComponentName name) {
|
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.
|
// 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.
|
// 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);
|
final Intent service = new Intent(this, BleProfileService.class);
|
||||||
bindService(service, mServiceConnection, 0);
|
bindService(service, serviceConnection, 0);
|
||||||
|
|
||||||
final WearableListView listView = findViewById(R.id.list);
|
final WearableListView listView = findViewById(R.id.list);
|
||||||
listView.setClickListener(this);
|
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)
|
.addApi(Wearable.API)
|
||||||
.addConnectionCallbacks(this)
|
.addConnectionCallbacks(this)
|
||||||
.addOnConnectionFailedListener(this)
|
.addOnConnectionFailedListener(this)
|
||||||
@@ -124,48 +124,48 @@ public class UARTConfigurationsActivity extends Activity implements GoogleApiCli
|
|||||||
final IntentFilter filter = new IntentFilter();
|
final IntentFilter filter = new IntentFilter();
|
||||||
filter.addAction(BleProfileService.BROADCAST_CONNECTION_STATE);
|
filter.addAction(BleProfileService.BROADCAST_CONNECTION_STATE);
|
||||||
filter.addAction(BleProfileService.BROADCAST_ERROR);
|
filter.addAction(BleProfileService.BROADCAST_ERROR);
|
||||||
LocalBroadcastManager.getInstance(this).registerReceiver(mServiceBroadcastReceiver, filter);
|
LocalBroadcastManager.getInstance(this).registerReceiver(serviceBroadcastReceiver, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
mGoogleApiClient.unregisterConnectionCallbacks(this);
|
googleApiClient.unregisterConnectionCallbacks(this);
|
||||||
mGoogleApiClient.unregisterConnectionFailedListener(this);
|
googleApiClient.unregisterConnectionFailedListener(this);
|
||||||
mGoogleApiClient = null;
|
googleApiClient = null;
|
||||||
|
|
||||||
// If we were bound to the service, disconnect and unbind. The service will terminate itself when disconnected.
|
// If we were bound to the service, disconnect and unbind. The service will terminate itself when disconnected.
|
||||||
if (mBinder != null) {
|
if (binder != null) {
|
||||||
mBinder.disconnect();
|
binder.disconnect();
|
||||||
}
|
}
|
||||||
unbindService(mServiceConnection);
|
unbindService(serviceConnection);
|
||||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(mServiceBroadcastReceiver);
|
LocalBroadcastManager.getInstance(this).unregisterReceiver(serviceBroadcastReceiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStart() {
|
protected void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
mGoogleApiClient.connect();
|
googleApiClient.connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStop() {
|
protected void onStop() {
|
||||||
super.onStop();
|
super.onStop();
|
||||||
Wearable.MessageApi.removeListener(mGoogleApiClient, this);
|
Wearable.MessageApi.removeListener(googleApiClient, this);
|
||||||
Wearable.DataApi.removeListener(mGoogleApiClient, this);
|
Wearable.DataApi.removeListener(googleApiClient, this);
|
||||||
mGoogleApiClient.disconnect();
|
googleApiClient.disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onConnected(final Bundle bundle) {
|
public void onConnected(final Bundle bundle) {
|
||||||
Wearable.DataApi.addListener(mGoogleApiClient, this);
|
Wearable.DataApi.addListener(googleApiClient, this);
|
||||||
Wearable.MessageApi.addListener(mGoogleApiClient, this);
|
Wearable.MessageApi.addListener(googleApiClient, this);
|
||||||
populateConfigurations();
|
populateConfigurations();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onConnectionSuspended(final int cause) {
|
public void onConnectionSuspended(final int cause) {
|
||||||
Wearable.DataApi.removeListener(mGoogleApiClient, this);
|
Wearable.DataApi.removeListener(googleApiClient, this);
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,7 +182,7 @@ public class UARTConfigurationsActivity extends Activity implements GoogleApiCli
|
|||||||
@Override
|
@Override
|
||||||
public void onMessageReceived(final MessageEvent messageEvent) {
|
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 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;
|
return;
|
||||||
|
|
||||||
switch (messageEvent.getPath()) {
|
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.
|
* This method read the UART configurations from the DataApi and populates the adapter with them.
|
||||||
*/
|
*/
|
||||||
private void populateConfigurations() {
|
private void populateConfigurations() {
|
||||||
if (mGoogleApiClient.isConnected()) {
|
if (googleApiClient.isConnected()) {
|
||||||
final PendingResult<DataItemBuffer> results = Wearable.DataApi.getDataItems(mGoogleApiClient, Uri.parse("wear:" + Constants.UART.CONFIGURATIONS), DataApi.FILTER_PREFIX);
|
final PendingResult<DataItemBuffer> results = Wearable.DataApi.getDataItems(googleApiClient, Uri.parse("wear:" + Constants.UART.CONFIGURATIONS), DataApi.FILTER_PREFIX);
|
||||||
results.setResultCallback(dataItems -> {
|
results.setResultCallback(dataItems -> {
|
||||||
final List<UartConfiguration> configurations = new ArrayList<>(dataItems.getCount());
|
final List<UartConfiguration> configurations = new ArrayList<>(dataItems.getCount());
|
||||||
for (int i = 0; i < dataItems.getCount(); ++i) {
|
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);
|
final UartConfiguration configuration = new UartConfiguration(dataMap, id);
|
||||||
configurations.add(configuration);
|
configurations.add(configuration);
|
||||||
}
|
}
|
||||||
mAdapter.setConfigurations(configurations);
|
adapter.setConfigurations(configurations);
|
||||||
dataItems.release();
|
dataItems.release();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,58 +31,60 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import no.nordicsemi.android.nrftoolbox.R;
|
import no.nordicsemi.android.nrftoolbox.R;
|
||||||
import no.nordicsemi.android.nrftoolbox.uart.domain.UartConfiguration;
|
import no.nordicsemi.android.nrftoolbox.uart.domain.UartConfiguration;
|
||||||
|
|
||||||
public class UARTConfigurationsAdapter extends WearableListView.Adapter {
|
public class UARTConfigurationsAdapter extends WearableListView.Adapter {
|
||||||
private final LayoutInflater mInflater;
|
private final LayoutInflater inflater;
|
||||||
private List<UartConfiguration> mConfigurations;
|
private List<UartConfiguration> configurations;
|
||||||
|
|
||||||
public UARTConfigurationsAdapter(final Context context) {
|
public UARTConfigurationsAdapter(final Context context) {
|
||||||
mInflater = LayoutInflater.from(context);
|
inflater = LayoutInflater.from(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Populates the adapter with list of configurations.
|
* Populates the adapter with list of configurations.
|
||||||
*/
|
*/
|
||||||
public void setConfigurations(final List<UartConfiguration> configurations) {
|
public void setConfigurations(final List<UartConfiguration> configurations) {
|
||||||
mConfigurations = configurations;
|
this.configurations = configurations;
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public WearableListView.ViewHolder onCreateViewHolder(final ViewGroup viewGroup, final int viewType) {
|
public WearableListView.ViewHolder onCreateViewHolder(@NonNull final ViewGroup viewGroup, final int viewType) {
|
||||||
return new ConfigurationViewHolder(mInflater.inflate(R.layout.configuration_item, viewGroup, false));
|
return new ConfigurationViewHolder(inflater.inflate(R.layout.configuration_item, viewGroup, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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;
|
final ConfigurationViewHolder viewHolder = (ConfigurationViewHolder) holder;
|
||||||
viewHolder.setConfiguration(mConfigurations.get(position));
|
viewHolder.setConfiguration(configurations.get(position));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getItemCount() {
|
public int getItemCount() {
|
||||||
return mConfigurations != null ? mConfigurations.size() : 0;
|
return configurations != null ? configurations.size() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ConfigurationViewHolder extends WearableListView.ViewHolder {
|
public static class ConfigurationViewHolder extends WearableListView.ViewHolder {
|
||||||
private UartConfiguration mConfiguration;
|
private UartConfiguration configuration;
|
||||||
private TextView mName;
|
private TextView name;
|
||||||
|
|
||||||
public ConfigurationViewHolder(final View itemView) {
|
public ConfigurationViewHolder(final View itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
|
|
||||||
mName = itemView.findViewById(R.id.name);
|
name = itemView.findViewById(R.id.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setConfiguration(final UartConfiguration configuration) {
|
private void setConfiguration(final UartConfiguration configuration) {
|
||||||
mConfiguration = configuration;
|
this.configuration = configuration;
|
||||||
mName.setText(configuration.getName());
|
name.setText(configuration.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
public UartConfiguration getConfiguration() {
|
public UartConfiguration getConfiguration() {
|
||||||
return mConfiguration;
|
return configuration;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
return service != null && service.getCharacteristic(UART_TX_CHARACTERISTIC_UUID) != null && service.getCharacteristic(UART_RX_CHARACTERISTIC_UUID) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private BluetoothGattCharacteristic mTXCharacteristic;
|
private BluetoothGattCharacteristic tXCharacteristic;
|
||||||
private BluetoothGattCharacteristic mRXCharacteristic;
|
private BluetoothGattCharacteristic rXCharacteristic;
|
||||||
private byte[] mOutgoingBuffer;
|
private byte[] outgoingBuffer;
|
||||||
private int mBufferOffset;
|
private int bufferOffset;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Deque<BleManager.Request> initGatt(final BluetoothGatt gatt) {
|
protected Deque<BleManager.Request> initGatt(final BluetoothGatt gatt) {
|
||||||
final BluetoothGattService service = gatt.getService(UART_SERVICE_UUID);
|
final BluetoothGattService service = gatt.getService(UART_SERVICE_UUID);
|
||||||
mTXCharacteristic = service.getCharacteristic(UART_TX_CHARACTERISTIC_UUID);
|
tXCharacteristic = service.getCharacteristic(UART_TX_CHARACTERISTIC_UUID);
|
||||||
mRXCharacteristic = service.getCharacteristic(UART_RX_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;
|
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).
|
// 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.
|
// 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)
|
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.
|
// 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<>();
|
// final LinkedList<BleProfileApi.Request> requests = new LinkedList<>();
|
||||||
// requests.add(BleProfileApi.Request.newEnableNotificationsRequest(mTXCharacteristic));
|
// requests.add(BleProfileApi.Request.newEnableNotificationsRequest(tXCharacteristic));
|
||||||
// return requests;
|
// return requests;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void release() {
|
protected void release() {
|
||||||
mTXCharacteristic = null;
|
tXCharacteristic = null;
|
||||||
mRXCharacteristic = null;
|
rXCharacteristic = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -102,13 +102,13 @@ public class UARTProfile extends BleProfile {
|
|||||||
@Override
|
@Override
|
||||||
protected void onCharacteristicWrite(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
|
protected void onCharacteristicWrite(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
|
||||||
// When the whole buffer has been sent
|
// When the whole buffer has been sent
|
||||||
final byte[] buffer = mOutgoingBuffer;
|
final byte[] buffer = outgoingBuffer;
|
||||||
if (mBufferOffset == buffer.length) {
|
if (bufferOffset == buffer.length) {
|
||||||
mOutgoingBuffer = null;
|
outgoingBuffer = null;
|
||||||
} else { // Otherwise...
|
} else { // Otherwise...
|
||||||
final int length = Math.min(buffer.length - mBufferOffset, MAX_PACKET_SIZE);
|
final int length = Math.min(buffer.length - bufferOffset, MAX_PACKET_SIZE);
|
||||||
getApi().enqueue(BleProfileApi.Request.newWriteRequest(mRXCharacteristic, buffer, mBufferOffset, length));
|
getApi().enqueue(BleProfileApi.Request.newWriteRequest(rXCharacteristic, buffer, bufferOffset, length));
|
||||||
mBufferOffset += length;
|
bufferOffset += length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,25 +118,25 @@ public class UARTProfile extends BleProfile {
|
|||||||
*/
|
*/
|
||||||
public void send(final String text) {
|
public void send(final String text) {
|
||||||
// Are we connected?
|
// Are we connected?
|
||||||
if (mRXCharacteristic == null)
|
if (rXCharacteristic == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// An outgoing buffer may not be null if there is already another packet being sent. We do nothing in this case.
|
// 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) {
|
if (!TextUtils.isEmpty(text) && outgoingBuffer == null) {
|
||||||
final byte[] buffer = mOutgoingBuffer = text.getBytes();
|
final byte[] buffer = outgoingBuffer = text.getBytes();
|
||||||
mBufferOffset = 0;
|
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),
|
// 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.
|
// 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
|
if (!writeRequest) { // no WRITE REQUEST property
|
||||||
final int length = Math.min(buffer.length, MAX_PACKET_SIZE);
|
final int length = Math.min(buffer.length, MAX_PACKET_SIZE);
|
||||||
mBufferOffset += length;
|
bufferOffset += length;
|
||||||
getApi().enqueue(BleProfileApi.Request.newWriteRequest(mRXCharacteristic, buffer, 0, length));
|
getApi().enqueue(BleProfileApi.Request.newWriteRequest(rXCharacteristic, buffer, 0, length));
|
||||||
} else { // there is WRITE REQUEST property, let's try Long Write
|
} else { // there is WRITE REQUEST property, let's try Long Write
|
||||||
mBufferOffset = buffer.length;
|
bufferOffset = buffer.length;
|
||||||
getApi().enqueue(BleProfileApi.Request.newWriteRequest(mRXCharacteristic, buffer, 0, buffer.length));
|
getApi().enqueue(BleProfileApi.Request.newWriteRequest(rXCharacteristic, buffer, 0, buffer.length));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user