/* * Catroid: An on-device visual programming system for Android devices * Copyright (C) 2010-2016 The Catrobat Team * (<http://developer.catrobat.org/credits>) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * An additional term exception under section 7 of the GNU Affero * General Public License, version 3, is available at * http://developer.catrobat.org/license_additional_term * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.catrobat.catroid.common.bluetooth; import com.google.common.base.Stopwatch; import org.catrobat.catroid.bluetooth.base.BluetoothConnection; import org.catrobat.catroid.bluetooth.base.BluetoothDevice; import org.catrobat.catroid.common.bluetooth.models.DeviceModel; import java.util.ArrayList; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; public final class ConnectionDataLogger { private BlockingQueue<byte[]> sentMessages = new LinkedBlockingQueue<byte[]>(); private BlockingQueue<byte[]> receivedMessages = new LinkedBlockingQueue<byte[]>(); private static final int TIMEOUT_SECONDS = 15; public byte[] getNextSentMessage() { return getNextSentMessage(0, 0); } public byte[] getNextSentMessage(int messageOffset) { return getNextSentMessage(messageOffset, 0); } public byte[] getNextSentMessage(int messageOffset, int messageByteOffset) { return getNextMessage(sentMessages, messageOffset, messageByteOffset); } public ArrayList<byte[]> getSentMessages(int messageCountToWaitFor) { return getSentMessages(0, messageCountToWaitFor); } public ArrayList<byte[]> getSentMessages(int messageByteOffset, int messageCountToWaitFor) { return getMessages(sentMessages, messageByteOffset, messageCountToWaitFor); } public byte[] getNextReceivedMessage() { return getNextReceivedMessage(0, 0); } public byte[] getNextReceivedMessage(int messageOffset) { return getNextReceivedMessage(messageOffset, 0); } public byte[] getNextReceivedMessage(int messageOffset, int messageByteOffset) { return getNextMessage(receivedMessages, messageOffset, messageByteOffset); } public ArrayList<byte[]> getReceivedMessages(int messageCountToWaitFor) { return getReceivedMessages(0, messageCountToWaitFor); } public ArrayList<byte[]> getReceivedMessages(int messageByteOffset, int messageCountToWaitFor) { return getMessages(receivedMessages, messageByteOffset, messageCountToWaitFor); } private static byte[] getNextMessage(BlockingQueue<byte[]> messages, int messageOffset, int messageByteOffset) { Stopwatch stopWatch = Stopwatch.createStarted(); for (int i = 0; i < messageOffset; i++) { byte[] message = pollMessage(messages, TIMEOUT_SECONDS - (int) stopWatch.elapsed(TimeUnit.SECONDS)); if (message == null) { return null; } } byte[] message = pollMessage(messages, TIMEOUT_SECONDS - (int) stopWatch.elapsed(TimeUnit.SECONDS)); if (message == null) { return null; } return BluetoothTestUtils.getSubArray(message, messageByteOffset); } private static ArrayList<byte[]> getMessages(BlockingQueue<byte[]> messages, int messageByteOffset, int messageCountToWaitFor) { if (messageCountToWaitFor == 0) { return getMessages(messages, messageByteOffset); } return waitForMessages(messages, messageByteOffset, messageCountToWaitFor); } private static ArrayList<byte[]> waitForMessages(BlockingQueue<byte[]> messages, int messageByteOffset, int messageCountToWaitFor) { ArrayList<byte[]> m = new ArrayList<byte[]>(); Stopwatch stopWatch = Stopwatch.createStarted(); do { byte[] message = pollMessage(messages, TIMEOUT_SECONDS - (int) stopWatch.elapsed(TimeUnit.SECONDS)); if (message == null) { return m; } m.add(BluetoothTestUtils.getSubArray(message, messageByteOffset)); } while (m.size() < messageCountToWaitFor && stopWatch.elapsed(TimeUnit.SECONDS) < TIMEOUT_SECONDS); return m; } private static ArrayList<byte[]> getMessages(BlockingQueue<byte[]> messages, int messageByteOffset) { ArrayList<byte[]> m = new ArrayList<byte[]>(); byte[] message = null; while ((message = messages.poll()) != null) { m.add(BluetoothTestUtils.getSubArray(message, messageByteOffset)); } return m; } private static byte[] pollMessage(BlockingQueue<byte[]> messages, int timeoutSeconds) { try { return messages.poll(timeoutSeconds, TimeUnit.SECONDS); } catch (InterruptedException e) { return null; } } private BluetoothConnection connectionProxy; private BluetoothLogger logger = new BluetoothLogger() { @Override public void logSentData(byte[] b) { sentMessages.add(b); } @Override public void logReceivedData(byte[] b) { receivedMessages.add(b); } @Override public void loggerAttached(BluetoothConnection proxy) { connectionProxy = proxy; } }; private ConnectionDataLogger(boolean local) { if (local) { connectionProxy = new LocalConnectionProxy(logger); BluetoothTestUtils.hookInConnection(connectionProxy); } else { BluetoothTestUtils.hookInConnectionFactoryWithBluetoothConnectionProxy(logger); } } private ConnectionDataLogger(DeviceModel deviceModel) { connectionProxy = new LocalConnectionProxy(logger, deviceModel); BluetoothTestUtils.hookInConnection(connectionProxy); } public static ConnectionDataLogger createLocalConnectionLogger() { return new ConnectionDataLogger(true); } public static ConnectionDataLogger createLocalConnectionLoggerWithTestDevice(BluetoothDevice testDevice) { BluetoothTestUtils.hookInTestDevice(testDevice); return new ConnectionDataLogger(true); } public static ConnectionDataLogger createLocalConnectionLoggerWithDeviceModel(DeviceModel deviceModel) { return new ConnectionDataLogger(deviceModel); } public static ConnectionDataLogger createLocalConnectionLoggerWithDeviceModelAndTestDevice(DeviceModel deviceModel, BluetoothDevice testDevice) { BluetoothTestUtils.hookInTestDevice(testDevice); return new ConnectionDataLogger(deviceModel); } public static ConnectionDataLogger createBluetoothConnectionLogger() { return new ConnectionDataLogger(false); } public static ConnectionDataLogger createBluetoothConnectionLoggerWithTestDevice(BluetoothDevice testDevice) { BluetoothTestUtils.hookInTestDevice(testDevice); return new ConnectionDataLogger(false); } public void disconnectAndDestroy() { if (connectionProxy != null) { connectionProxy.disconnect(); } BluetoothTestUtils.resetConnectionHooks(); } public BluetoothConnection getConnectionProxy() { return connectionProxy; } BluetoothLogger getLogger() { return logger; } }