private void handleActivityMetadata(byte[] value) { if (value.length != activityMetadataLength) { return; } // byte 0 is the data type: 1 means that each minute is represented by a triplet of bytes int dataType = value[0]; // byte 1 to 6 represent a timestamp GregorianCalendar timestamp = MiBandDateConverter.rawBytesToCalendar(value, 1); // counter of all data held by the band int totalDataToRead = (value[7] & 0xff) | ((value[8] & 0xff) << 8); totalDataToRead *= (dataType == MiBandService.MODE_REGULAR_DATA_LEN_MINUTE) ? 3 : 1; // counter of this data block int dataUntilNextHeader = (value[9] & 0xff) | ((value[10] & 0xff) << 8); dataUntilNextHeader *= (dataType == MiBandService.MODE_REGULAR_DATA_LEN_MINUTE) ? 3 : 1; // there is a total of totalDataToRead that will come in chunks (3 bytes per minute if dataType // == 1 (MiBandService.MODE_REGULAR_DATA_LEN_MINUTE)), // these chunks are usually 20 bytes long and grouped in blocks // after dataUntilNextHeader bytes we will get a new packet of 11 bytes that should be parsed // as we just did if (activityStruct.isFirstChunk() && dataUntilNextHeader != 0) { GB.toast( getContext() .getString( R.string.user_feedback_miband_activity_data_transfer, DateTimeUtils.formatDurationHoursMinutes((totalDataToRead / 3), TimeUnit.MINUTES), DateFormat.getDateTimeInstance().format(timestamp.getTime())), Toast.LENGTH_LONG, GB.INFO); } LOG.info( "total data to read: " + totalDataToRead + " len: " + (totalDataToRead / 3) + " minute(s)"); LOG.info( "data to read until next header: " + dataUntilNextHeader + " len: " + (dataUntilNextHeader / 3) + " minute(s)"); LOG.info( "TIMESTAMP: " + DateFormat.getDateTimeInstance().format(timestamp.getTime()) + " magic byte: " + dataUntilNextHeader); activityStruct.startNewBlock(timestamp, dataUntilNextHeader); }