Related
i am making an app that records a video and then displays this video on another activity.
the problem is that this video cannot be played right away, i would have to record the video, and then restart the android app for it to show. otherwise it shows me a message that
says: "can't play this video".
Moreover the thing that i really dont understand is that i tried it on an older phone of android version 11 and it works perfectly, but for some reason on the new phone it doesn't
i have made some research and i think it has something to do with the storage permissions but i am not sure since i tried fixing it with no luck.
what can i do to fix this?
public class MainActivity extends AppCompatActivity {
CameraManager CamMan;
boolean flag = false;
public static boolean FirstDirectoryCreated;
CameraSource cameraSource;
Button seeVideos;
public static File LeakedVids;
public static boolean isDirectoryCreated;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.CAMERA}, 1);
}
seeVideos = findViewById(R.id.seeVideos);
init();
createFiles();
CamMan = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
seeVideos.setOnClickListener(v -> goToVideos());
}
private void goToVideos() {
Intent intent = new Intent(this, ShowVideo.class);
startActivity(intent);
}
#Override
public void onBackPressed(){
Intent a = new Intent(Intent.ACTION_MAIN);
a.addCategory(Intent.CATEGORY_HOME);
a.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(a);
}
private void createFiles () {
File EyeTracker = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES), "Eye Tracker");
FirstDirectoryCreated = EyeTracker.exists() || EyeTracker.mkdirs();
if (FirstDirectoryCreated) {
LeakedVids = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES) + File.separator
+ "Eye Tracker", "Leaked Videos");
isDirectoryCreated = LeakedVids.exists() || LeakedVids.mkdirs();
}
}
private void init () {
flag = true;
initCameraSource();
}
//method to create camera source from faceFactoryDaemon class
private void initCameraSource () {
FaceDetector detector = new FaceDetector.Builder(this)
.setTrackingEnabled(true)
.setClassificationType(FaceDetector.ALL_CLASSIFICATIONS)
.setMode(FaceDetector.ACCURATE_MODE)
.build();
detector.setProcessor(new MultiProcessor.Builder(new FaceTrackerDaemon(MainActivity.this)).build());
cameraSource = new CameraSource.Builder(this, detector)
.setRequestedPreviewSize(1024, 768)
.setFacing(CameraSource.CAMERA_FACING_BACK)
.setRequestedFps(30.0f)
.build();
try {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.CAMERA}, 1);
return;
}
cameraSource.start();
} catch (IOException e) {
Toast.makeText(MainActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
#Override
protected void onResume () {
super.onResume();
if (cameraSource != null) {
try {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.CAMERA}, 1);
return;
}
cameraSource.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
protected void onPause () {
super.onPause();
if (cameraSource != null) {
cameraSource.stop();
}
}
#Override
protected void onDestroy () {
super.onDestroy();
if (cameraSource != null) {
cameraSource.release();
}
}
//update view
#SuppressLint("SetTextI18n")
public void updateMainView (Condition condition){
switch (condition) {
case USER_EYES_OPEN:
openCam();
break;
case FACE_NOT_FOUND:
break;
}
}
public void openCam () {
Intent intent = new Intent(this, VideoPreview.class);
startActivity(intent);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
}
VideoPreview
public class VideoPreview extends AppCompatActivity {
private VideoCapture<Recorder> videoCapture = null;
private Recording recording = null;
private ExecutorService cameraExecutor;
private ActivityVideoPreviewBinding viewBinding;
Timer timer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_video_preview);
viewBinding = ActivityVideoPreviewBinding.inflate(getLayoutInflater());
setContentView(viewBinding.getRoot());
startCamera();
timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
captureVideo();
}
}, 173);
timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
stopRec();
}
}, 6000);
timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
backToMain();
}
}, 6100);
cameraExecutor = Executors.newSingleThreadExecutor();
}
private void stopRec() {
Recording curRecording = recording;
if (curRecording != null) {
// Stop the current recording session.
curRecording.stop();
recording = null;
}
}
#Override
public void onBackPressed() {
Toast.makeText(this, "Ntek Ntor Ya Zabre", Toast.LENGTH_SHORT).show();
}
private void captureVideo() {
/* MediaStoreOutputOptions mediaStoreOutputOptions = (new androidx.camera.video.MediaStoreOutputOptions
.Builder(this.getContentResolver(), android.provider.MediaStore.Video.Media.EXTERNAL_CONTENT_URI))
.build(); */
String name = "LeakedVideo_" + System.currentTimeMillis() + ".mp4";
File vids = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES) + File.separator
+ "Eye Tracker" + File.separator + "Leaked Videos", name);
FileOutputOptions fileOutputOptions = new FileOutputOptions.Builder(vids).build();
if (videoCapture != null) {
PendingRecording recording = (videoCapture.getOutput())
.prepareRecording(this, fileOutputOptions);
this.recording = recording.start((ContextCompat.getMainExecutor(this)), videoRecordEvent -> {
});
}
}
private void startCamera() {
ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(this);
cameraProviderFuture.addListener((() -> {
ProcessCameraProvider var10000 = null;
try {
var10000 = cameraProviderFuture.get();
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
assert var10000 != null;
Intrinsics.checkNotNullExpressionValue(var10000, "cameraProviderFuture.get()");
ProcessCameraProvider cameraProvider = var10000;
Preview preview = new Preview.Builder()
.build();
preview.setSurfaceProvider(viewBinding.viewFinder.getSurfaceProvider());
Recorder recorder = (new Recorder.Builder())
.setQualitySelector(QualitySelector.from(Quality.HIGHEST))
.build();
videoCapture = VideoCapture.withOutput(recorder);
CameraSelector cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA;
try {
cameraProvider.unbindAll();
cameraProvider
.bindToLifecycle(this, cameraSelector, preview, videoCapture);
} catch (Exception exc) {
Log.e("CameraXApp", "Use case binding failed", exc);
}
}), ContextCompat.getMainExecutor(this));
}
protected void onDestroy() {
super.onDestroy();
cameraExecutor.shutdown();
}
public void backToMain() {
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
}
}
ShowVideo:
public class ShowVideo extends AppCompatActivity {
private static final String TAG = "MainActivity";
private CardStackLayoutManager manager;
public static File[] files;
public static List<Video> videos;
public static int num;
File newFile;
String dir;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.show_video);
if (ActivityCompat.checkSelfPermission(this, READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{READ_EXTERNAL_STORAGE}, 1);
}
dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES).getPath();
files = MainActivity.LeakedVids.listFiles();
num = 1;
videos = new ArrayList<>();
CardStackView cardStackView = findViewById(R.id.card_stack_view);
if (files.length > 0) {
videos.add(new Video(files[files.length - 1].getPath()));
Adapter adapter = new Adapter(videos);
cardStackView.setAdapter(adapter);
} else {
Toast.makeText(this, "No Videos to show", Toast.LENGTH_SHORT).show();
}
manager = new CardStackLayoutManager(this, new CardStackListener() {
#Override
public void onCardDragging(Direction direction, float ratio) {
}
#Override
public void onCardSwiped(Direction direction) {
Log.d(TAG, "onCardSwiped: p=" + manager.getTopPosition() + " d=" + direction);
if (direction == Direction.Right) {
if (files.length == 1) {
newFile = new File(dir, files[files.length - 1].getName());
FileChannel outputChannel = null;
FileChannel inputChannel = null;
try {
outputChannel = new FileOutputStream(newFile).getChannel();
inputChannel = new FileInputStream(files[files.length - 1]).getChannel();
inputChannel.transferTo(0, inputChannel.size(), outputChannel);
inputChannel.close();
files[files.length - 1].delete();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (inputChannel != null) {
try {
inputChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (outputChannel != null) {
try {
outputChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
} else {
newFile = new File(dir, files[files.length - num].getName());
FileChannel outputChannel = null;
FileChannel inputChannel = null;
try {
outputChannel = new FileOutputStream(newFile).getChannel();
inputChannel = new FileInputStream(files[files.length - num]).getChannel();
inputChannel.transferTo(0, inputChannel.size(), outputChannel);
inputChannel.close();
files[files.length - num].delete();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (inputChannel != null) {
try {
inputChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (outputChannel != null) {
try {
outputChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
if (direction == Direction.Left) {
if (files.length == 1) {
files[files.length - 1].delete();
} else {
files[files.length - num].delete();
}
}
if (files != null) {
if (files.length > num) {
num++;
videos.add(new Video(files[files.length - num].getPath()));
}
}
Adapter adapter = new Adapter(videos);
cardStackView.setAdapter(adapter);
}
#Override
public void onCardRewound() {
Log.d(TAG, "onCardRewound: " + manager.getTopPosition());
}
#Override
public void onCardCanceled() {
Log.d(TAG, "onCardRewound: " + manager.getTopPosition());
}
#Override
public void onCardAppeared(View view, int position) {
}
#Override
public void onCardDisappeared(View view, int position) {
}
});
manager.setStackFrom(StackFrom.None);
manager.setVisibleCount(3);
manager.setTranslationInterval(8.0f);
manager.setScaleInterval(0.95f);
manager.setSwipeThreshold(0.3f);
manager.setMaxDegree(20.0f);
manager.setDirections(Direction.FREEDOM);
manager.setCanScrollHorizontal(true);
manager.setCanScrollVertical(false);
manager.setSwipeableMethod(SwipeableMethod.Manual);
manager.setOverlayInterpolator(new LinearInterpolator());
cardStackView.setLayoutManager(manager);
cardStackView.setItemAnimator(new DefaultItemAnimator());
}
#Override
public void onBackPressed(){
Intent a = new Intent(this, MainActivity.class);
startActivity(a);
}
}
Adapter:
public class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> {
private List<Video> videos;
public Adapter(List<Video> videos) {
this.videos = videos;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int position) {
//LayoutInflater inflater = LayoutInflater.from(parent.getContext());
//View view = inflater.inflate(R.layout.item_card, parent, false);
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_card, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
holder.setData(videos.get(position));
holder.itemView.setOnClickListener(v -> {
Intent intent = new Intent(holder.itemView.getContext(), DetailActivity.class);
intent.putExtra("param", videos.get(position).getPath());
holder.itemView.getContext().startActivity(intent);
});
}
#Override
public int getItemCount() {
return videos.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public static VideoView videoView;
ViewHolder(#NonNull View itemView) {
super(itemView);
videoView = itemView.findViewById(R.id.item_video);
}
void setData(Video video) {
videoView.setVideoPath(video.getPath());
videoView.setOnPreparedListener(MediaPlayer::start);
videoView.setOnCompletionListener(MediaPlayer::start);
}
}
public List<Video> getItems() {
return videos;
}
public void setItems(List<Video> items) {
this.videos = items;
}
}
the problem is that when i open the 'ShowVideo' class the video doesnt play until i restart the app
pls help.
I'm trying to make an app that can send and receive data via bluetooth from arduino. The part where i send the data is fairly simple so I've managed to get it right. I got stuck at receiving data.
My program has 2 layouts. First there is a layout with a CONNECT button and some buttons that change the layout. This is the code:
Public class MainActivity extends AppCompatActivity {
ImageButton test, manual,connect;
Button back;
private BluetoothAdapter mbluetoothAdapter;
protected AlertDialog.Builder builder;
ConnectThread mBluetooth = new ConnectThread();
String mBluetoothName = "";
String mBluetoothAdress = "";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final Context context = this;
//final LayoutInflater factory = getLayoutInflater();
//final View textEntryView = factory.inflate(R.layout.activity_main);
builder = new AlertDialog.Builder(this);
mbluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
connect = (ImageButton) findViewById(R.id.connect);
test = (ImageButton) findViewById(R.id.test);
manual = (ImageButton) findViewById(R.id.manual);
test.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(context,SecondActivity.class );
context.startActivity(intent);
}
});
manual.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(context,SecondActivity.class );
context.startActivity(intent);
}
});
connect.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!mbluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivity(enableBtIntent);
} else {
if (!mBluetooth.mBluetoothAddress.equals("")) {//if another connection is already exits then close it first
stopAllActivities();
} else {
try {
Intent serverIntent = new Intent(MainActivity.this, DeviceListActivity.class);
startActivityForResult(serverIntent, Helper.REQUEST_CONNECT_DEVICE);
} catch (Exception e) {
showToast(getString(R.string.errorOccured) + ": " + e.getMessage());
e.printStackTrace();
}
}
}
}
});
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case Helper.REQUEST_CONNECT_DEVICE:
if (resultCode == Activity.RESULT_OK) {
mBluetoothName = data.getExtras().getString(Helper.EXTRA_BLUETOOTH_NAME);
mBluetoothAdress = data.getExtras().getString(Helper.EXTRA_BLUETOOTH_ADDRESS);
// setBluetoothInfo();
showToast(R.string.connectedDevice + mBluetoothName);
if (!mBluetoothAdress.equals("")) {
if (!mBluetooth.connect(mBluetoothAdress)){
}
}
}
break;
}
}
The SecondActivity contains the main purpose of this app: To send and receive data. This is how it looks like:
public class SecondActivity extends AppCompatActivity {
final Context context = this;
Button back;
ImageButton btnup, btndown, btnright, btnleft;
ConnectThread mBluetooth = new ConnectThread();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnup = (ImageButton) findViewById(R.id.btnup);
btndown = (ImageButton) findViewById(R.id.btndown);
btnleft = (ImageButton) findViewById(R.id.btnleft);
btnright = (ImageButton) findViewById(R.id.btnright);
final TextView direction = (TextView) findViewById(R.id.text_direction);
final TextView steering = (TextView) findViewById(R.id.steering_direction);
final TextView speed = (TextView) findViewById(R.id.speed);
final TextView battery = (TextView) findViewById(R.id.batery);
final Chronometer chronometer = (Chronometer) findViewById(R.id.chronometer);
btndown.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
mBluetooth.write("2");
direction.setText(R.string.Backwards);
} else if (event.getAction() == MotionEvent.ACTION_UP) {
mBluetooth.write("x");
direction.setText(R.string.blank);
}
return false;
}
});
Note: I didnt post the whole code because i have more buttons with the exact same code as the one above.
For the Bluetooth connection i have 2 separate classes one called ConnectThread:
public class ConnectThread {
BluetoothAdapter mBluetoothAdapter = null;
BluetoothSocket mSocket = null;
OutputStream mOutStream = null;
InputStream mInStream=null;
String mBluetoothAddress = "";
public boolean connect(String bluetoothAddress) {
if (!mBluetoothAddress.equals(bluetoothAddress) && !mBluetoothAddress.equals("")) {
close();
}
mBluetoothAddress = bluetoothAddress;
if (mBluetoothAdapter == null) {
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
}
if (mBluetoothAdapter == null) {
return false;
}
if (!mBluetoothAdapter.isEnabled()) {
return false;
}
try {
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(mBluetoothAddress);
if (mSocket == null) {
mSocket = device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
mSocket.connect();
}
} catch (IOException e) {
mSocket = null;
e.printStackTrace();
return false;
}
try {
mOutStream = mSocket.getOutputStream();
} catch (IOException e) {
mOutStream = null;
e.printStackTrace();
return false;
}
return true;
}
public boolean check() {
if (mBluetoothAdapter == null) {
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
}
if (mBluetoothAdapter == null) {
return false;
}
if (!mBluetoothAdapter.isEnabled()) {
return false;
}
if (!mSocket.isConnected()) {
return false;
}
return true;
}
public boolean close() {
try {
if (mOutStream != null) {
mOutStream.close();
}
if (mSocket != null) {
mSocket.close();
}
} catch (IOException e) {
e.printStackTrace();
return false;
}
mOutStream = null;
mSocket = null;
return true;
}
public boolean write(String strData) {
byte[] buffer = strData.getBytes();
try {
if (mOutStream != null && mBluetoothAdapter.getState() == BluetoothAdapter.STATE_ON) {
mOutStream.write(buffer);
}
else {
return false;
}
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
}
And the other one DeviceListActivity:
public class DeviceListActivity extends Activity {
private BluetoothAdapter mBtAdapter;
private ArrayAdapter<String> mPairedDevicesArrayAdapter;
private ArrayAdapter<String> mNewDevicesArrayAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Setup the window
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.device_list);
// Set result CANCELED incase the user backs out
setResult(Activity.RESULT_CANCELED);
// Initialize the button to perform device discovery
Button scanButton = (Button) findViewById(R.id.button_scan);
scanButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (mBtAdapter == null)
return;
doDiscovery();
v.setVisibility(View.GONE);
}
});
// Initialize array adapters. One for already paired devices and
// one for newly discovered devices
mPairedDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name);
mNewDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name);
// Find and set up the ListView for paired devices
ListView pairedListView = (ListView) findViewById(R.id.paired_devices);
pairedListView.setAdapter(mPairedDevicesArrayAdapter);
pairedListView.setOnItemClickListener(mDeviceClickListener);
// Find and set up the ListView for newly discovered devices
ListView newDevicesListView = (ListView) findViewById(R.id.new_devices);
newDevicesListView.setAdapter(mNewDevicesArrayAdapter);
newDevicesListView.setOnItemClickListener(mDeviceClickListener);
// Register for broadcasts when a device is discovered
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
this.registerReceiver(mReceiver, filter);
// Register for broadcasts when discovery has finished
filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
this.registerReceiver(mReceiver, filter);
// Get the local Bluetooth adapter
mBtAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBtAdapter == null) {
mPairedDevicesArrayAdapter.add("DUMMY\n00:00:00:00:00:00");
return;
}
// Get a set of currently paired devices
Set<BluetoothDevice> pairedDevices = mBtAdapter.getBondedDevices();
// If there are paired devices, add each one to the ArrayAdapter
if (pairedDevices.size() > 0) {
findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE);
for (BluetoothDevice device : pairedDevices) {
mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
} else {
String noDevices = getResources().getText(R.string.none_paired).toString();
mPairedDevicesArrayAdapter.add(noDevices);
}
}
#Override
protected void onDestroy() {
super.onDestroy();
// Make sure we're not doing discovery anymore
if (mBtAdapter != null)
mBtAdapter.cancelDiscovery();
// Unregister broadcast listeners
this.unregisterReceiver(mReceiver);
}
/**
* Start device discover with the BluetoothAdapter
*/
private void doDiscovery() {
if (mBtAdapter == null)
return;
// Indicate scanning in the title
setProgressBarIndeterminateVisibility(true);
setTitle(R.string.scanning);
// Turn on sub-title for new devices
findViewById(R.id.title_new_devices).setVisibility(View.VISIBLE);
// If we're already discovering, stop it
if (mBtAdapter.isDiscovering()) {
mBtAdapter.cancelDiscovery();
}
// Request discover from BluetoothAdapter
mBtAdapter.startDiscovery();
}
// The on-click listener for all devices in the ListViews
private AdapterView.OnItemClickListener mDeviceClickListener = new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> av, View v, int arg2, long arg3) {
if (mBtAdapter != null) {
// Cancel discovery because it's costly and we're about to connect
mBtAdapter.cancelDiscovery();
}
// Get the device MAC address, which is the last 17 chars in the View
String info = ((TextView) v).getText().toString();
String name = info.substring(0, info.length() - 18);
String address = info.substring(info.length() - 17);
// Create the result Intent and include the MAC address
Intent intent = new Intent();
intent.putExtra(Helper.EXTRA_BLUETOOTH_ADDRESS, address);
intent.putExtra(Helper.EXTRA_BLUETOOTH_NAME, name);
// Set result and finish this Activity
setResult(Activity.RESULT_OK, intent);
finish();
}
};
// The BroadcastReceiver that listens for discovered devices and
// changes the title when discovery is finished
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// When discovery finds a device
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// Get the BluetoothDevice object from the Intent
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// If it's already paired, skip it, because it's been listed already
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
for (int i = 0; i < mNewDevicesArrayAdapter.getCount(); i++) {
if (mNewDevicesArrayAdapter.getItem(i).equals(device.getName() + "\n" + device.getAddress())) {
return;
}
}
mNewDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
// When discovery is finished, change the Activity title
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
setProgressBarIndeterminateVisibility(false);
setTitle(R.string.select_device);
if (mNewDevicesArrayAdapter.getCount() == 0) {
String noDevices = getResources().getText(R.string.none_found).toString();
mNewDevicesArrayAdapter.add(noDevices);
}
}
}
};
}
I want to update two TextView with the data i receive from arduino. The data would look something like #first_data,second_data* where # is the start of data series and * the end. I would appreciate if you can help me with some advice/code how to do that. I am pretty new to java and I still dont fully understand how everything works.
Once you get the Bluetooth socket you could use its stream to read/write the content.
...
m_Input = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
m_Output = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
...
// reading from stream
m_Input.read(buffer, readBytes, 1) ;
you could use
m_Input.available()
to check if is any data available into stream. Otherwise the read method will block until you will read the number of bytes you specified as third argument.
int readBytes=0;
while(readBytes < expectedBytes){
timeout = 0;
while((m_Input.available()) == 0 && timeout < ReadTimeout) {
timeout+=250;
// throws interrupted exception
Thread.sleep(250);// let control to other threads
}
if(timeout >= ReadTimeout){
// throw new timeout exception
}
if (m_Input.read(buffer, readBytes, 1) == -1) {
// throw stream/socket closed
}
readBytes++;
}
Ad for writing use write method
...
//writting to stream
m_Output.write(buffer,..);
I'm developing a bluetooth app to control an Arduino board, but now I made some mistakes: when I try to make a connection from my phone, it displays an AlertDialog (it is OK) and a lot of Toasts (they're called from onSensorChanged).
The BT module connected to the board is OK (tested with other apps), so the problem is Java: I can't make a connection to my BT module. Unfortunately, Android Studio doesn't give me any logcat or errors.
This is my code:
/* imports... */
public class MainActivity extends AppCompatActivity implements SensorEventListener {
/* Bluetooth */
private static final int REQUEST_ENABLE_BT = 1;
private String selectedDevice = "";
static final UUID defaultUUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); //This SPP UUID should work for most devices.
//private boolean isConnected = false;
BluetoothAdapter bluetoothAdapter;
BluetoothSocket bluetoothSocket;
/* Is in full screen = ? */
private boolean FullScreenState = true;
/* Views */
private SeekBar steeringWheel;
private SeekBar forwardsSpeed;
private SeekBar backwardsSpeed;
private Toolbar toolbar;
/* Dialogs */
AlertDialog.Builder errorDialog;
AlertDialog.Builder listDialog;
ProgressDialog progressDialog;
/* Accelerometer managers */
Sensor accelerometer;
SensorManager sensorManager;
float Y = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
(...)
/* Views */
steeringWheel = (SeekBar) findViewById(R.id.Steering_wheel);
forwardsSpeed = (SeekBar) findViewById(R.id.Forwards_speed);
backwardsSpeed = (SeekBar) findViewById(R.id.Backwards_speed);
/* listDialogs */
listDialog = new AlertDialog.Builder(this);
listDialog.setCancelable(true);
listDialog.setTitle(R.string.app_name);
//listDialog.setMessage("Select a device:");
listDialog.setIcon(R.drawable.launcher_icon);
//listDialog.setView(devicesListView);
listDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
/* errorDialog */
errorDialog = new AlertDialog.Builder(this);
errorDialog.setCancelable(false);
errorDialog.setTitle(R.string.app_name);
errorDialog.setIcon(R.drawable.error_material);
errorDialog.setPositiveButton("I got it", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
/* Set the full screen and keep the screen always on... */
/* Accelerometer initializer... */
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
...
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
...
if (id == R.id.toolbar_connect) {
initializeBT();
return true;
} else if (id == R.id.toolbar_settings) {
/* Settings activity. Coming soon. */
return true;
} else if (id == R.id.toolbar_disconnect) {
if (bluetoothSocket != null) {
try {
bluetoothSocket.close();
} catch (IOException e) {
errorDialog.setMessage("Disconnection error!");
errorDialog.show();
}
}
return true;
}
...
}
#Override
public void onSensorChanged(SensorEvent event) {
/* Get the axes */
Y = event.values[1];
/* Set the steering wheel position */
steeringWheel.setProgress((int)Y + 10);
send(String.valueOf(steeringWheel.getProgress()));
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
...
}
private class connect extends AsyncTask<Void, Void, Void> {
private boolean connectionSuccess = false;
#Override
protected void onPreExecute() {
progressDialog = ProgressDialog.show(MainActivity.this, "Connecting...", "Creating bluetooth connection");
}
#Override
protected Void doInBackground(Void... devices) {
try {
if (bluetoothSocket == null) {
//if ((bluetoothSocket == null) || (!isConnected)) {
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
BluetoothDevice arduino = bluetoothAdapter.getRemoteDevice(selectedDevice);
bluetoothSocket = arduino.createInsecureRfcommSocketToServiceRecord(defaultUUID);
BluetoothAdapter.getDefaultAdapter().cancelDiscovery();
bluetoothSocket.connect();
connectionSuccess = true;
}
} catch (IOException e) {
connectionSuccess = false;
}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
if (!connectionSuccess) {
errorDialog.setMessage("Connection error!");
errorDialog.show();
bluetoothSocket = null;
} else {
Toast.makeText(getApplicationContext(), "Successfully connected", Toast.LENGTH_LONG).show();
//isConnected = true;
}
progressDialog.dismiss();
}
}
void initializeBT() {
/* Check for Bluetooth support */
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter == null) {
errorDialog.setMessage("Unfortunately, Bluetooth connection isn't supported on your device.");
errorDialog.show();
} else if (!bluetoothAdapter.isEnabled()) {
/* Bluetooth disables -> enable it */
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
} else {
devicesPrompt();
}
}
void devicesPrompt() {
//final ArrayList<String> devicesList = new ArrayList()<String>;
Set<BluetoothDevice> pairedDevices;
final ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1);
pairedDevices = bluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
for(BluetoothDevice bluetoothDevice : pairedDevices) {
/* Get the device's name and the address */
//devicesList.add(bt.getName() + "\n" + bt.getAddress());
adapter.add(bluetoothDevice.getName() + "\n" + bluetoothDevice.getAddress());
}
} else {
Toast.makeText(getApplicationContext(), "No paired Bluetooth devices found!", Toast.LENGTH_LONG).show();
}
listDialog.setAdapter(adapter, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
//Log.d("RoverBluetooth!!", String.valueOf(which));
//;
String info = adapter.getItem(which);
selectedDevice = info.substring(info.length() - 17);
new connect().execute();
dialog.dismiss();
}
});
listDialog.show();
}
public void send(String message) {
message = message + "/r";
if (bluetoothSocket != null) {
try {
bluetoothSocket.getOutputStream().write(message.getBytes());
} catch (IOException e) {
Toast.makeText(getApplicationContext(), "Error during sending", Toast.LENGTH_SHORT).show();
Log.d("RoverBluetooth errors", e.toString());
}
}
}
public void buttonsActions(View view) {
int viewId = view.getId();
if (viewId == R.id.Forwards_button) { //ON
send(String.valueOf(forwardsSpeed.getProgress() + 1000));
} else if (viewId == R.id.Stop_button) { //OFF
send("21");
} else if (viewId == R.id.Backwards_button) { //Backwards
send(String.valueOf(backwardsSpeed.getProgress() + 1500));
} else if (viewId == R.id.Light_ON) { //Light ON
send("22");
} else if (viewId == R.id.Light_OFF) { //Light OFF
send("23");
}
}
}
I already wrote a class to make a bluetooth connection between Android and Arduino. I suppose you're using a HC-06 (or -05 ?). My code is on github:
https://github.com/omaflak/Bluetooth-Android
I also wrote a tutorial on my blog, you may want to take a look at it:
https://causeyourestuck.io/2015/12/14/communication-between-android-and-hc-06-module/
Good luck!
I am trying to find when and where CH34xAndroidDriver.isConnected() value becomes true.
I have tried to find out and display its value in a toast. can anybody explain it clearly.
public class UartLoopBackActivity extends Activity {
public static final String TAG = "com.wch.wchusbdriver";
private static final String ACTION_USB_PERMISSION = "com.wch.wchusbdriver.USB_PERMISSION";
/* thread to read the data */
public readThread handlerThread;
protected final Object ThreadLock = new Object();
/* declare UART interface variable */
public CH34xAndroidDriver uartInterface;
// byte timeout; // time out
public Context global_context;
public boolean isConfiged = false;
public boolean READ_ENABLE = false;
public SharedPreferences sharePrefSettings;
Drawable originalDrawable;
public String act_string;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
/* create editable text objects */
readText = (EditText) findViewById(R.id.ReadValues);
// writeText = (EditText) findViewById(R.id.WriteValues);
global_context = this;
configButton = (Button) findViewById(R.id.configButton);
originalDrawable = configButton.getBackground();
readBuffer = new char[512];
baudRate = 9600;
stopBit = 1;
dataBit = 8;
parity = 0;
flowControl = 0;
configButton.setOnClickListener(new OpenDeviceListener());
// writeButton.setOnClickListener(new OnClickedWriteButton());
// writeButton.setEnabled(false);
//
uartInterface = new CH34xAndroidDriver(
(UsbManager) getSystemService(Context.USB_SERVICE), this,
ACTION_USB_PERMISSION);
act_string = getIntent().getAction();
if (-1 != act_string.indexOf("android.intent.action.MAIN")) {
Log.d(TAG, "android.intent.action.MAIN");
} else if (-1 != act_string
.indexOf("android.hardware.usb.action.USB_DEVICE_ATTACHED")) {
Log.d(TAG, "android.hardware.usb.action.USB_DEVICE_ATTACHED");
}
if (!uartInterface.UsbFeatureSupported()) {
Toast.makeText(this, "No Support USB host API", Toast.LENGTH_SHORT)
.show();
readText.setText("No Support USB host API");
uartInterface = null;
Toast.makeText(global_context,
"148k" + ((Boolean) uartInterface.isConnected()),
Toast.LENGTH_SHORT).show();
}
getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
if (READ_ENABLE == false) {
READ_ENABLE = true;
handlerThread = new readThread(handler);
handlerThread.start();
Toast.makeText(global_context,"155k" + ((Boolean) uartInterface.isConnected()),Toast.LENGTH_SHORT).show();
}
}
public class OpenDeviceListener implements View.OnClickListener {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
boolean flags;
Toast.makeText(global_context,"170" + ((Boolean) uartInterface.isConnected()),Toast.LENGTH_SHORT).show();
Log.d("onClick", "12");
if (false == isConfiged) {
Log.d("onClick", "58");
isConfiged = true;
Log.d("onClick", "98");
// writeButton.setEnabled(true);
if (uartInterface.isConnected()) {
Log.d("onClick", "100");
flags = uartInterface.UartInit();
if (!flags) {
Log.d(TAG, "Init Uart Error");
Toast.makeText(global_context, "Init Uart Error",
Toast.LENGTH_SHORT).show();
} else {
if (uartInterface.SetConfig(baudRate, dataBit, stopBit,
parity, flowControl)) {
Log.d(TAG, "Configed");
}
}
}
if (isConfiged == true) {
Toast.makeText(global_context,"193" + ((Boolean) uartInterface.isConnected()),Toast.LENGTH_SHORT).show();
Log.d("onClick", "200");
configButton.setEnabled(false);
}
}
}
}
public void onHomePressed() {
onBackPressed();
}
public void onBackPressed() {
super.onBackPressed();
}
protected void onResume() {
super.onResume();
if (2 == uartInterface.ResumeUsbList()) {
uartInterface.CloseDevice();
Log.d(TAG, "Enter onResume Error");
}
}
protected void onPause() {
super.onPause();
}
protected void onStop() {
if (READ_ENABLE == true) {
READ_ENABLE = false;
}
super.onStop();
}
protected void onDestroy() {
if (uartInterface != null) {
if (uartInterface.isConnected()) {
uartInterface.CloseDevice();
}
uartInterface = null;
}
super.onDestroy();
}
final Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
if (actualNumBytes != 0x00) {
readText.append(String.copyValueOf(readBuffer, 0,
actualNumBytes));
Toast.makeText(global_context,"269k" + ((Boolean) uartInterface.isConnected()),Toast.LENGTH_SHORT).show();
actualNumBytes = 0;
}
}
};
/* usb input data handler */
private class readThread extends Thread {
Handler mHandler;
/* constructor */
Handler mhandler;
readThread(Handler h) {
mhandler = h;
this.setPriority(Thread.MIN_PRIORITY);
}
public void run() {
while (READ_ENABLE) {
Message msg = mhandler.obtainMessage();
try {
Thread.sleep(50);
} catch (InterruptedException e) {
}
// Log.d(TAG, "Thread");
synchronized (ThreadLock) {
if (uartInterface != null) {
actualNumBytes = uartInterface.ReadData(readBuffer, 64);
if (actualNumBytes > 0) {
mhandler.sendMessage(msg);
}
}
}
}
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.uart_loop_back, menu);
return true;
}
}
upto line 74 (Toast.makeText(global_context,"155k" + ((Boolean) uartInterface.isConnected()),Toast.LENGTH_SHORT).show();) i found it returns false but when the onClick() is called it return true. why if any body has answer pls check it.
Thanks
the method ResumeUsbList() enables usb connection and changes isConnected() to true. if ResumeUsbList() fails it returns 2
Check your Activity's onResume()
I am using Sinch and Parse for my instant messaging system integrated in our application, and I have two concerns.
1) For some reason, I am receiving the following error when the messaging activity is displayed: The message client did not start". Furthermore, the message does not seem to go through in Sinch and not reflected visually in the application.
Below is the activity code (when the user clicks on the "quick chat" button, it takes them to the messaging activity page.
Below is the activity code for the messaging activity
public class MessagingActivity extends Activity implements ServiceConnection, MessageClientListener {
private String recipientId;
private Button sendButton;
private EditText messageBodyField;
private String messageBody;
private MessageService.MessageServiceInterface messageService;
private MessageAdapter messageAdapter;
private ListView messagesList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.messaging);
doBind();
messagesList = (ListView) findViewById(R.id.listMessages);
messageAdapter = new MessageAdapter(this);
messagesList.setAdapter(messageAdapter);
Intent intent = getIntent();
recipientId = intent.getStringExtra("Name");
messageBodyField = (EditText) findViewById(R.id.messageBodyField);
sendButton = (Button) findViewById(R.id.sendButton);
sendButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
sendMessage();
}
});
}
private void sendMessage() {
messageBodyField = (EditText) findViewById(R.id.messageBodyField);
messageBody = messageBodyField.getText().toString();
if (messageBody.isEmpty()) {
Toast.makeText(this, "Please enter a message", Toast.LENGTH_LONG).show();
return;
}
//Here is where you will actually send the message throught Sinch
messageService.sendMessage(recipientId, messageBody);
messageBodyField.setText("");
}
private void doBind() {
Intent serviceIntent = new Intent(this, MessageService.class);
bindService(serviceIntent, this, BIND_AUTO_CREATE);
}
#Override
public void onDestroy() {
unbindService(this);
super.onDestroy();
}
#Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
//Define the messaging service and add a listener
messageService = (MessageService.MessageServiceInterface) iBinder;
messageService.addMessageClientListener(this);
if (!messageService.isSinchClientStarted()) {
Toast.makeText(this, "The message client did not start."
,Toast.LENGTH_LONG).show();
}
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
messageService = null;
}
#Override
public void onMessageDelivered(MessageClient client, MessageDeliveryInfo deliveryInfo) {
//Intentionally left blank
}
#Override
public void onMessageFailed(MessageClient client, Message message,
MessageFailureInfo failureInfo) {
//Notify the user if message fails to send
Toast.makeText(this, "Message failed to send.", Toast.LENGTH_LONG).show();
}
#Override
public void onIncomingMessage(MessageClient client, Message message) {
messageAdapter.addMessage(message, MessageAdapter.DIRECTION_INCOMING);
}
#Override
public void onMessageSent(MessageClient client, Message message, String recipientId) {
messageAdapter.addMessage(message, MessageAdapter.DIRECTION_OUTGOING);
}
#Override
public void onShouldSendPushData(MessageClient client, Message message, List<PushPair> pushPairs) {
//Intentionally left blank
}
}
I have verified that the APP_KEY, the APP_SECRET and ENVIRONMENT matches what was recorded on Sinch.
I have tried this both on the emulator, and on a physical device.
Thanks in advance
Code service
public class MessageService extends Service implements SinchClientListener {
private static final String APP_KEY = "XXXXX";
private static final String APP_SECRET = "YYYYY";
private static final String ENVIRONMENT = "sandbox.sinch.com";
private final MessageServiceInterface serviceInterface = new MessageServiceInterface();
private SinchClient sinchClient = null;
private MessageClient messageClient = null;
private String currentUserId;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
currentUserId = ParseUser.getCurrentUser().getObjectId().toString();
if (currentUserId != null && !isSinchClientStarted()) {
startSinchClient(currentUserId);
}
return super.onStartCommand(intent, flags, startId);
}
public void startSinchClient(String username) {
sinchClient = Sinch.getSinchClientBuilder().context(this).userId(username).applicationKey(APP_KEY)
.applicationSecret(APP_SECRET).environmentHost(ENVIRONMENT).build();
sinchClient.addSinchClientListener(this);
sinchClient.setSupportMessaging(true);
sinchClient.setSupportActiveConnectionInBackground(true);
sinchClient.checkManifest();
sinchClient.start();
}
private boolean isSinchClientStarted() {
return sinchClient != null && sinchClient.isStarted();
}
#Override
public void onClientFailed(SinchClient client, SinchError error) {
sinchClient = null;
}
#Override
public void onClientStarted(SinchClient client) {
client.startListeningOnActiveConnection();
messageClient = client.getMessageClient();
}
#Override
public void onClientStopped(SinchClient client) {
sinchClient = null;
}
public void stop() {
if (isSinchClientStarted()) {
sinchClient.stop();
sinchClient.removeSinchClientListener(this);
}
sinchClient = null;
}
#Override
public IBinder onBind(Intent intent) {
return serviceInterface;
}
#Override
public void onLogMessage(int level, String area, String message) {
//Intentionally left blank
}
#Override
public void onRegistrationCredentialsRequired(SinchClient client, ClientRegistration clientRegistration) {
//Intentionally left blank
}
public void sendMessage(String recipientUserId, String textBody) {
if (messageClient != null) {
WritableMessage message = new WritableMessage(recipientUserId, textBody);
messageClient.send(message);
}
}
public void addMessageClientListener(MessageClientListener listener) {
if (messageClient != null) {
messageClient.addMessageClientListener(listener);
}
}
public void removeMessageClientListener(MessageClientListener listener) {
if (messageClient != null) {
messageClient.removeMessageClientListener(listener);
}
}
public class MessageServiceInterface extends Binder {
public void sendMessage(String recipientUserId, String textBody) {
MessageService.this.sendMessage(recipientUserId, textBody);
}
public void addMessageClientListener(MessageClientListener listener) {
MessageService.this.addMessageClientListener(listener);
}
public void removeMessageClientListener(MessageClientListener listener) {
MessageService.this.removeMessageClientListener(listener);
}
public boolean isSinchClientStarted() {
return MessageService.this.isSinchClientStarted();
}
}
}
2) Limit: I would like to set a limit, where a only 25 messages would be available between a particular party.
Thanks in advance, and if you need any clarification, let me know.
Update 3
When user clicks on this button, he is taking to the MessagingActivity with the person he has been matched to based upon the below criteria
final Button ibutton = (Button) this.findViewById(R.id.btnQuickChat);
idrinks.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
openConversation();
}
private void openConversation() {
// TODO Auto-generated method stub
ParseQuery<ParseUser> query = ParseUser.getQuery();
query.whereNotEqualTo("objectId", ParseUser.getCurrentUser()
.getObjectId());
query.setLimit(1);
query.findInBackground(new FindCallback<ParseUser>() {
public void done(List<ParseUser> user, ParseException e) {
if (e == null) {
Intent intent = new Intent(getApplicationContext(), MessagingActivity.class);
intent.putExtra("RECIPIENT_ID", user.get(0).getObjectId());
startActivity(intent);
} else {
Toast.makeText(getApplicationContext(),
"Error finding that user",
Toast.LENGTH_SHORT).show();
}
}
});
}
});
MessagingActivity (nearly same as one provided in tutorial):
public class MessagingActivity extends Activity {
private String recipientId;
private EditText messageBodyField;
private String messageBody;
private MessageService.MessageServiceInterface messageService;
private MessageAdapter messageAdapter;
private ListView messagesList;
private String currentUserId;
private ServiceConnection serviceConnection = new MyServiceConnection();
private MessageClientListener messageClientListener = new MyMessageClientListener();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.messaging);
bindService(new Intent(this, MessageService.class), serviceConnection, BIND_AUTO_CREATE);
Intent intent = getIntent();
recipientId = intent.getStringExtra("RECIPIENT_ID");
currentUserId = ParseUser.getCurrentUser().getObjectId();
messagesList = (ListView) findViewById(R.id.listMessages);
messageAdapter = new MessageAdapter(this);
messagesList.setAdapter(messageAdapter);
populateMessageHistory();
messageBodyField = (EditText) findViewById(R.id.messageBodyField);
findViewById(R.id.sendButton).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
sendMessage();
}
});
}
//get previous messages from parse & display
private void populateMessageHistory() {
String[] userIds = {currentUserId, recipientId};
ParseQuery<ParseObject> query = ParseQuery.getQuery("ParseMessage");
query.whereContainedIn("senderId", Arrays.asList(userIds));
query.whereContainedIn("recipientId", Arrays.asList(userIds));
query.orderByAscending("createdAt");
query.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> messageList, com.parse.ParseException e) {
if (e == null) {
for (int i = 0; i < messageList.size(); i++) {
WritableMessage message = new WritableMessage(messageList.get(i).get("recipientId").toString(), messageList.get(i).get("messageText").toString());
if (messageList.get(i).get("senderId").toString().equals(currentUserId)) {
messageAdapter.addMessage(message, MessageAdapter.DIRECTION_OUTGOING);
} else {
messageAdapter.addMessage(message, MessageAdapter.DIRECTION_INCOMING);
}
}
}
}
});
}
private void sendMessage() {
messageBody = messageBodyField.getText().toString();
if (messageBody.isEmpty()) {
Toast.makeText(this, "Please enter a message", Toast.LENGTH_LONG).show();
return;
}
messageService.sendMessage(recipientId, messageBody);
messageBodyField.setText("");
}
#Override
public void onDestroy() {
messageService.removeMessageClientListener(messageClientListener);
unbindService(serviceConnection);
super.onDestroy();
}
private class MyServiceConnection implements ServiceConnection {
#Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
messageService = (MessageService.MessageServiceInterface) iBinder;
messageService.addMessageClientListener(messageClientListener);
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
messageService = null;
}
}
private class MyMessageClientListener implements MessageClientListener {
#Override
public void onMessageFailed(MessageClient client, Message message,
MessageFailureInfo failureInfo) {
Toast.makeText(MessagingActivity.this, "Message failed to send.", Toast.LENGTH_LONG).show();
}
#Override
public void onIncomingMessage(MessageClient client, Message message) {
if (message.getSenderId().equals(recipientId)) {
WritableMessage writableMessage = new WritableMessage(message.getRecipientIds().get(0), message.getTextBody());
messageAdapter.addMessage(writableMessage, MessageAdapter.DIRECTION_INCOMING);
}
}
#Override
public void onMessageSent(MessageClient client, Message message, String recipientId) {
final WritableMessage writableMessage = new WritableMessage(message.getRecipientIds().get(0), message.getTextBody());
//only add message to parse database if it doesn't already exist there
ParseQuery<ParseObject> query = ParseQuery.getQuery("ParseMessage");
query.whereEqualTo("sinchId", message.getMessageId());
query.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> messageList, com.parse.ParseException e) {
if (e == null) {
if (messageList.size() == 0) {
ParseObject parseMessage = new ParseObject("ParseMessage");
parseMessage.put("senderId", currentUserId);
parseMessage.put("recipientId", writableMessage.getRecipientIds().get(0));
parseMessage.put("messageText", writableMessage.getTextBody());
parseMessage.put("sinchId", writableMessage.getMessageId());
parseMessage.saveInBackground();
messageAdapter.addMessage(writableMessage, MessageAdapter.DIRECTION_OUTGOING);
}
}
}
});
}
#Override
public void onMessageDelivered(MessageClient client, MessageDeliveryInfo deliveryInfo) {}
#Override
public void onShouldSendPushData(MessageClient client, Message message, List<PushPair> pushPairs) {}
}
}
MessageService activity
public class MessageService extends Service implements SinchClientListener {
private static final String APP_KEY = "61b1bfc0-b82a-44f5-ab68-dedca69ead8c";
private static final String APP_SECRET = "jrFrLr8Adkm0Na4nLdASDw==";
private static final String ENVIRONMENT = "sandbox.sinch.com";
private final MessageServiceInterface serviceInterface = new MessageServiceInterface();
private SinchClient sinchClient = null;
private MessageClient messageClient = null;
private String currentUserId;
private LocalBroadcastManager broadcaster;
private Intent broadcastIntent = new Intent("com.dooba.beta.matchOptionActivity");
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
currentUserId = ParseUser.getCurrentUser().getObjectId();
if (currentUserId != null && !isSinchClientStarted()) {
startSinchClient(currentUserId);
}
broadcaster = LocalBroadcastManager.getInstance(this);
return super.onStartCommand(intent, flags, startId);
}
public void startSinchClient(String username) {
sinchClient = Sinch.getSinchClientBuilder().context(this).userId(username).applicationKey(APP_KEY)
.applicationSecret(APP_SECRET).environmentHost(ENVIRONMENT).build();
sinchClient.addSinchClientListener(this);
sinchClient.setSupportMessaging(true);
sinchClient.setSupportActiveConnectionInBackground(true);
sinchClient.checkManifest();
sinchClient.start();
}
private boolean isSinchClientStarted() {
return sinchClient != null && sinchClient.isStarted();
}
#Override
public void onClientFailed(SinchClient client, SinchError error) {
broadcastIntent.putExtra("success", false);
broadcaster.sendBroadcast(broadcastIntent);
sinchClient = null;
}
#Override
public void onClientStarted(SinchClient client) {
broadcastIntent.putExtra("success", true);
broadcaster.sendBroadcast(broadcastIntent);
client.startListeningOnActiveConnection();
messageClient = client.getMessageClient();
}
#Override
public void onClientStopped(SinchClient client) {
sinchClient = null;
}
#Override
public IBinder onBind(Intent intent) {
return serviceInterface;
}
#Override
public void onLogMessage(int level, String area, String message) {
}
#Override
public void onRegistrationCredentialsRequired(SinchClient client, ClientRegistration clientRegistration) {
}
public void sendMessage(String recipientUserId, String textBody) {
if (messageClient != null) {
WritableMessage message = new WritableMessage(recipientUserId, textBody);
messageClient.send(message);
}
}
public void addMessageClientListener(MessageClientListener listener) {
if (messageClient != null) {
messageClient.addMessageClientListener(listener);
}
}
public void removeMessageClientListener(MessageClientListener listener) {
if (messageClient != null) {
messageClient.removeMessageClientListener(listener);
}
}
public class MessageServiceInterface extends Binder {
public void sendMessage(String recipientUserId, String textBody) {
MessageService.this.sendMessage(recipientUserId, textBody);
}
public void addMessageClientListener(MessageClientListener listener) {
MessageService.this.addMessageClientListener(listener);
}
public void removeMessageClientListener(MessageClientListener listener) {
MessageService.this.removeMessageClientListener(listener);
}
public boolean isSinchClientStarted() {
return MessageService.this.isSinchClientStarted();
}
}
Message adapter activity:
public class MessageAdapter extends BaseAdapter {
public static final int DIRECTION_INCOMING = 0;
public static final int DIRECTION_OUTGOING = 1;
private List<Pair<WritableMessage, Integer>> messages;
private LayoutInflater layoutInflater;
public MessageAdapter(Activity activity) {
layoutInflater = activity.getLayoutInflater();
messages = new ArrayList<Pair<WritableMessage, Integer>>();
}
public void addMessage(WritableMessage message, int direction) {
messages.add(new Pair(message, direction));
notifyDataSetChanged();
}
#Override
public int getCount() {
return messages.size();
}
#Override
public Object getItem(int i) {
return messages.get(i);
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public int getViewTypeCount() {
return 2;
}
#Override
public int getItemViewType(int i) {
return messages.get(i).second;
}
#Override
public View getView(int i, View convertView, ViewGroup viewGroup) {
int direction = getItemViewType(i);
//show message on left or right, depending on if
//it's incoming or outgoing
if (convertView == null) {
int res = 0;
if (direction == DIRECTION_INCOMING) {
res = R.layout.message_right;
} else if (direction == DIRECTION_OUTGOING) {
res = R.layout.message_left;
}
convertView = layoutInflater.inflate(res, viewGroup, false);
}
WritableMessage message = messages.get(i).first;
TextView txtMessage = (TextView) convertView.findViewById(R.id.txtMessage);
txtMessage.setText(message.getTextBody());
return convertView;
}
}
I wrote the tutorial you're following, and actually just updated it yesterday to fix your first problem. Check out http://tutorial.sinch.com/android-messaging-tutorial/#show-spinner to see the updates. Instead of showing a toast message when the service is not started, the new version will show a progress dialog (loading spinner) until the service has either started or failed to start.
Could you clarify your second question?
Just declare your service in manifest. I had the same problem and it solved it.