Skip to content

Instantly share code, notes, and snippets.

@Ayyagaries
Created March 29, 2019 13:36
Show Gist options
  • Save Ayyagaries/09a8b752d614795b8d1b10403cff6457 to your computer and use it in GitHub Desktop.
Save Ayyagaries/09a8b752d614795b8d1b10403cff6457 to your computer and use it in GitHub Desktop.
MainActivity.java
package com.ix.ebadgesdk.sample;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import no.nordicsemi.android.ble.data.Data;
import android.Manifest;
import android.app.Dialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Bundle;
import android.text.InputType;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ToggleButton;
import com.afollestad.materialdialogs.MaterialDialog;
import com.afollestad.materialdialogs.folderselector.FileChooserDialog;
import com.afollestad.materialdialogs.simplelist.MaterialSimpleListAdapter;
import com.afollestad.materialdialogs.simplelist.MaterialSimpleListItem;
import com.github.rtoshiro.util.format.SimpleMaskFormatter;
import com.github.rtoshiro.util.format.text.MaskTextWatcher;
import com.ix.ebadgesdk.CmdController;
import com.ix.ebadgesdk.EBadgeBleManager;
import com.ix.ebadgesdk.EBadgeBleManagerCallback;
import com.ix.ebadgesdk.Utils;
import com.ix.ebadgesdk.bean.ImageConfig;
import com.ix.ebadgesdk.bean.ImageData;
import org.apache.commons.io.IOUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.UUID;
import static com.ix.ebadgesdk.EBadgeBleManager.bytesToHex;
public class MainActivity extends AppCompatActivity implements FileChooserDialog.FileCallback {
private static final String TAG = "BLESample";
private final static String DEFAULT_IMG_DATA = "000000b6ffdbffb6000000000000b6ffffffb60000006db7b6dbffffffdbb6b749ffffffffffffffffffffffffdbb7b7b7b7b7b7b7dbffffdb00000000000000dbffffdb00000000000000dbffffdb92929292929292dbffffffdbdbdbdbdbdbdbffffffdb00000000000000dbffffdb00000000000000dbffffdb92929292929292dbffffffdbdbdbdbdbdbdbffffffdb00000000000000dbffffdb00000000000000dbffffdb92929292929292dbffffffdbdbdbdbdbdbdbffffffdb00000000000000dbffffdb00000000000000dbffffdb6e6e6e6e6e6e6edbffffffffffffffffffffffff6edbdbdbdbdbdbdbdbdb6e";
private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
private BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
if (device.getName() != null && device.getName().startsWith("R5") && !(mBLEDeviceAddressSet.contains(device.getAddress()))) {
mBLEDeviceAddressSet.add(device.getAddress());
mMaterialSimpleListAdapter.add(new MaterialSimpleListItem.Builder(MainActivity.this)
.id(device.getAddress().hashCode())
.tag(device)
.content("Name: " + device.getName() + " Mac: " + device.getAddress())
.build());
}
}
};
private BluetoothGatt mBluetoothGatt;
private EBadgeBleManager mBleManager;
private MaterialSimpleListAdapter mMaterialSimpleListAdapter;
private HashSet<String> mBLEDeviceAddressSet = new HashSet<>();
private RecyclerView mRecyclerView;
private LogAdapter mLogAdapter;
private String mImgDataHexString = DEFAULT_IMG_DATA;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = findViewById(R.id.rv_ble_log);
mLogAdapter = new LogAdapter();
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
mRecyclerView.setAdapter(mLogAdapter);
mBleManager = new EBadgeBleManager(getApplicationContext());
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.READ_EXTERNAL_STORAGE},
0);
mMaterialSimpleListAdapter = new MaterialSimpleListAdapter(new MaterialSimpleListAdapter.Callback() {
@Override
public void onMaterialListItemSelected(MaterialDialog dialog, int index, MaterialSimpleListItem item) {
dialog.cancel();
connectToDevice(((BluetoothDevice) item.getTag()));
}
});
mBluetoothManager = (BluetoothManager)
getSystemService(Context.BLUETOOTH_SERVICE);
showNearByBLEDevice();
getPairedDevices();
byte[] result = CmdController.addFlashImageTest();
byte[] addPageTestResult = CmdController.addPageTest();
byte[] refreshResult = CmdController.refreshTest();
Log.d(TAG, "onCreate: " + bytesToHex(result));
Log.d(TAG, "addPageTestResult: " + bytesToHex(addPageTestResult));
Log.d(TAG, "refreshResult: " + bytesToHex(refreshResult));
}
private void showNearByBLEDevice() {
new MaterialDialog.Builder(this).adapter(mMaterialSimpleListAdapter, null).cancelable(false).show();
}
private void connectToDevice(BluetoothDevice device) {
mBleManager.setGattCallbacks(new EBadgeBleManagerCallback() {
@Override
public void onError(@NonNull BluetoothDevice device, @NonNull String message, int errorCode) {
Log.d(TAG, "onError: " + message + ", code:" + errorCode);
}
@Override
public void onNotificationDataReceive(@NonNull BluetoothDevice device, @NonNull Data data) {
super.onNotificationDataReceive(device, data);
mLogAdapter.addLog("Notify: " + bytesToHex(data.getValue()));
mRecyclerView.smoothScrollToPosition(mLogAdapter.getItemCount() - 1);
}
@Override
public void log(int priority, @NonNull String message) {
super.log(priority, message);
mLogAdapter.addLog(message);
mRecyclerView.smoothScrollToPosition(mLogAdapter.getItemCount() - 1);
}
});
mBleManager.connect(device).useAutoConnect(false).enqueue();
}
public void customCmd(View view) {
new MaterialDialog.Builder(this)
.title("cmd")
.inputType(InputType.TYPE_CLASS_TEXT)
.input("", "", (dialog, input) -> mBleManager.customCmd(input.toString()));//.show();
new FileChooserDialog.Builder(this)
.tag("customCmd")
.extensionsFilter(".txt") // Optional extension filter, will override mimeType()
.show(this); // an AppCompatActivity which implements FileCallback
}
@Override
public void onFileSelection(@NonNull FileChooserDialog dialog, @NonNull File file) {
dialog.dismiss();
String tag = "";
if (dialog.getTag() != null) {
tag = dialog.getTag();
}
switch (tag) {
case "customCmd":
new Thread(() -> {
try {
FileInputStream fin = new FileInputStream(file);
String result = IOUtils.toString(fin, Charset.defaultCharset());
mBleManager.customCmd(result);
} catch (IOException e) {
e.printStackTrace();
}
}).run();
break;
case "imageData":
final Dialog loadingDialog = new MaterialDialog.Builder(this).title("Decoding...")
.progress(true, 0)
.show();
new Thread(() -> {
try {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap bitmap = BitmapFactory.decodeFile(file.getPath(), options);
mImgDataHexString = Utils.byteArrayToHexString(bitmapTo8BitImage(bitmap));
loadingDialog.dismiss();
} catch (Exception e) {
e.printStackTrace();
}
}).run();
break;
}
}
private byte[] bitmapTo8BitImage(Bitmap bitmap) {
int[] pixels = new int[bitmap.getWidth() * bitmap.getHeight()];
bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0,
bitmap.getWidth(), bitmap.getHeight());
ByteBuffer eightByteBuffer = ByteBuffer.allocate(pixels.length);
for (int i = 0; i < pixels.length; i++) {
int p = pixels[i];
int red = Color.red(p);
int green = Color.green(p);
int blue = Color.blue(p);
byte p1Rgb = (byte) (((int) Math.round(red / 255.0 * 7.0) << 5) |
((int) Math.round(green / 255.0 * 7.0) << 2) |
((int) Math.round(blue / 255.0 * 3.0)));
eightByteBuffer.put(p1Rgb);
}
return eightByteBuffer.array();
}
@Override
public void onFileChooserDismissed(@NonNull FileChooserDialog dialog) {
}
public void sendImage(View view) {
//mBleManager.sendImageBuffer();
showSendImageDialog();
}
private void showSendImageDialog() {
LinearLayout linearLayout = new LinearLayout(this);
linearLayout.setOrientation(LinearLayout.VERTICAL);
ViewGroup.LayoutParams editTextLayoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
final EditText imageIdEdit = new EditText(this);
imageIdEdit.setHint("ImageId");
imageIdEdit.setInputType(InputType.TYPE_CLASS_NUMBER);
imageIdEdit.setText("1");
final EditText widthEdit = new EditText(this);
widthEdit.setHint("Width");
widthEdit.setInputType(InputType.TYPE_CLASS_NUMBER);
widthEdit.setText("11");
final EditText heightEdit = new EditText(this);
heightEdit.setHint("Height");
heightEdit.setInputType(InputType.TYPE_CLASS_NUMBER);
heightEdit.setText("22");
final Button imageDataBtn = new Button(this);
imageDataBtn.setAllCaps(false);
imageDataBtn.setText("ImageFile");
imageDataBtn.setOnClickListener(v -> {
new FileChooserDialog.Builder(this)
.tag("imageData")
.mimeType("image/*")
//.extensionsFilter(".txt") // Optional extension filter, will override mimeType()
.show(this); // an AppCompatActivity which implements FileCallback
});
linearLayout.addView(imageIdEdit, editTextLayoutParams);
linearLayout.addView(widthEdit, editTextLayoutParams);
linearLayout.addView(heightEdit, editTextLayoutParams);
linearLayout.addView(imageDataBtn);
new MaterialDialog.Builder(this)
.title("Send Image")
.customView(linearLayout, true)
.positiveText(android.R.string.ok)
.negativeText(android.R.string.cancel)
.onPositive((dialog, which) -> {
int imageId = Integer.parseInt(imageIdEdit.getText().toString());
int width = Integer.parseInt(widthEdit.getText().toString());
int height = Integer.parseInt(heightEdit.getText().toString());
sendImg(imageId, width, height);
})
.show();
}
private void sendImg(int imageId, int width, int height) {
ImageData imageData = new ImageData();
imageData.id = imageId;
imageData.width = width;
imageData.height = height;
imageData.data = Utils.hexStringToByteArray(mImgDataHexString);
mBleManager.sendImageBuffer(imageData);
mImgDataHexString = DEFAULT_IMG_DATA;
}
private void showSetImageDialog() {
LinearLayout linearLayout = new LinearLayout(this);
linearLayout.setOrientation(LinearLayout.VERTICAL);
ViewGroup.LayoutParams editTextLayoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
final EditText pageIdEdit = new EditText(this);
pageIdEdit.setHint("PageId");
pageIdEdit.setInputType(InputType.TYPE_CLASS_NUMBER);
pageIdEdit.setText("1");
final ToggleButton backgroundToggle = new ToggleButton(this);
backgroundToggle.setTextOn("White");
backgroundToggle.setTextOff("Black");
backgroundToggle.setChecked(false);
final EditText expiredEdit = new EditText(this);
expiredEdit.setHint("ExpiredTime: 2019/10/10 11:12:13");
expiredEdit.setInputType(InputType.TYPE_CLASS_NUMBER);
expiredEdit.setText("2019/10/10 11:12:13");
SimpleMaskFormatter smf = new SimpleMaskFormatter("NNNN/NN/NN NN:NN:NN");
MaskTextWatcher mtw = new MaskTextWatcher(expiredEdit, smf);
expiredEdit.addTextChangedListener(mtw);
final EditText imageIdEdit = new EditText(this);
imageIdEdit.setHint("ImageId");
imageIdEdit.setInputType(InputType.TYPE_CLASS_NUMBER);
imageIdEdit.setText("1");
final EditText xEdit = new EditText(this);
xEdit.setHint("X");
xEdit.setInputType(InputType.TYPE_CLASS_NUMBER);
xEdit.setText("100");
final EditText yEdit = new EditText(this);
yEdit.setHint("Y");
yEdit.setInputType(InputType.TYPE_CLASS_NUMBER);
yEdit.setText("200");
final ToggleButton invertToggle = new ToggleButton(this);
invertToggle.setTextOn("Invert");
invertToggle.setTextOff("Normal");
invertToggle.setChecked(false);
linearLayout.addView(pageIdEdit, editTextLayoutParams);
linearLayout.addView(backgroundToggle);
linearLayout.addView(expiredEdit, editTextLayoutParams);
linearLayout.addView(imageIdEdit, editTextLayoutParams);
linearLayout.addView(xEdit, editTextLayoutParams);
linearLayout.addView(yEdit, editTextLayoutParams);
linearLayout.addView(invertToggle);
new MaterialDialog.Builder(this)
.title("Send Image")
.customView(linearLayout, true)
.positiveText(android.R.string.ok)
.negativeText(android.R.string.cancel)
.onPositive((dialog, which) -> {
int pageId = Integer.parseInt(pageIdEdit.getText().toString());
boolean background = backgroundToggle.isChecked();
Date date = parseDate(expiredEdit.getText().toString());
int imageId = Integer.parseInt(imageIdEdit.getText().toString());
int x = Integer.parseInt(xEdit.getText().toString());
int y = Integer.parseInt(yEdit.getText().toString());
boolean invert = invertToggle.isChecked();
ImageConfig imageConfig = new ImageConfig();
imageConfig.imageId = imageId;
imageConfig.x = x;
imageConfig.y = y;
imageConfig.invert = invert;
List<ImageConfig> configList = new ArrayList<>();
configList.add(imageConfig);
mBleManager.setImageConfig(pageId, background ? 1 : 0, date, configList);
})
.show();
}
private Date parseDate(String dataString) {
Date date = new Date();
SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.US);
try {
date = format.parse(dataString);
System.out.println(date);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
public void setPage(View view) {
showSetImageDialog();
}
private void showRefreshDialog() {
LinearLayout linearLayout = new LinearLayout(this);
linearLayout.setOrientation(LinearLayout.VERTICAL);
ViewGroup.LayoutParams editTextLayoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
final EditText pageIdEdit = new EditText(this);
pageIdEdit.setHint("ImageId");
pageIdEdit.setInputType(InputType.TYPE_CLASS_NUMBER);
pageIdEdit.setText("1");
linearLayout.addView(pageIdEdit, editTextLayoutParams);
new MaterialDialog.Builder(this)
.title("Send Image")
.customView(linearLayout, true)
.positiveText(android.R.string.ok)
.negativeText(android.R.string.cancel)
.onPositive((dialog, which) -> {
int pageId = Integer.parseInt(pageIdEdit.getText().toString());
mBleManager.refresh(pageId);
})
.show();
}
public void refresh(View view) {
showRefreshDialog();
}
public void clean(View view) {
mBleManager.clean();
}
private void getPairedDevices() {
for (BluetoothDevice device : mBluetoothManager.getConnectedDevices(BluetoothProfile.GATT)) {
if (device.getName() != null && device.getName().startsWith("R5") && !(mBLEDeviceAddressSet.contains(device.getAddress()))) {
mBLEDeviceAddressSet.add(device.getAddress());
mMaterialSimpleListAdapter.add(new MaterialSimpleListItem.Builder(MainActivity.this)
.id(device.getAddress().hashCode())
.tag(device)
.content("Name(Paired): " + device.getName() + " Mac: " + device.getAddress())
.build());
}
}
}
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i + 1), 16));
}
return data;
}
private void getBatteryLevel(BluetoothGatt gatt) {
for (BluetoothGattService service : gatt.getServices()) {
Log.d(TAG, "service list: " + service.getUuid());
}
BluetoothGattService service = gatt.getService(UUID.fromString("0000180f-0000-1000-8000-00805f9b34fb"));
Log.d(TAG, "battery service == null: " + String.valueOf(service == null));
if (service != null) {
gatt.readCharacteristic(service.getCharacteristic(UUID.fromString("00002a19-0000-1000-8000-00805f9b34fb")));
}
}
@Override
protected void onStart() {
super.onStart();
mBluetoothAdapter.startLeScan(leScanCallback);
}
@Override
protected void onStop() {
super.onStop();
mBluetoothAdapter.stopLeScan(leScanCallback);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mBleManager != null) {
mBleManager.disconnect();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment