Hello guys. So i'm trying to make a app that will play a aac stream from an online radio station. I managed to build the project but i get this error when running it.
Code:
05-27 06:12:00.734: E/AndroidRuntime(450): FATAL EXCEPTION: main
05-27 06:12:00.734: E/AndroidRuntime(450): java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.spoledge.aacplay/com.spoledge.aacplay.AACPlayerActivity}: java.lang.ClassNotFoundException: com.spoledge.aacplay.AACPlayerActivity in loader dalvik.system.PathClassLoader[/data/app/com.spoledge.aacplay-2.apk]
05-27 06:12:00.734: E/AndroidRuntime(450): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1569)
05-27 06:12:00.734: E/AndroidRuntime(450): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1663)
05-27 06:12:00.734: E/AndroidRuntime(450): at android.app.ActivityThread.access$1500(ActivityThread.java:117)
05-27 06:12:00.734: E/AndroidRuntime(450): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931)
05-27 06:12:00.734: E/AndroidRuntime(450): at android.os.Handler.dispatchMessage(Handler.java:99)
05-27 06:12:00.734: E/AndroidRuntime(450): at android.os.Looper.loop(Looper.java:123)
05-27 06:12:00.734: E/AndroidRuntime(450): at android.app.ActivityThread.main(ActivityThread.java:3683)
05-27 06:12:00.734: E/AndroidRuntime(450): at java.lang.reflect.Method.invokeNative(Native Method)
05-27 06:12:00.734: E/AndroidRuntime(450): at java.lang.reflect.Method.invoke(Method.java:507)
05-27 06:12:00.734: E/AndroidRuntime(450): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
05-27 06:12:00.734: E/AndroidRuntime(450): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
05-27 06:12:00.734: E/AndroidRuntime(450): at dalvik.system.NativeStart.main(Native Method)
05-27 06:12:00.734: E/AndroidRuntime(450): Caused by: java.lang.ClassNotFoundException: com.spoledge.aacplay.AACPlayerActivity in loader dalvik.system.PathClassLoader[/data/app/com.spoledge.aacplay-2.apk]
05-27 06:12:00.734: E/AndroidRuntime(450): at dalvik.system.PathClassLoader.findClass(PathClassLoader.java:240)
05-27 06:12:00.734: E/AndroidRuntime(450): at java.lang.ClassLoader.loadClass(ClassLoader.java:551)
05-27 06:12:00.734: E/AndroidRuntime(450): at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
05-27 06:12:00.734: E/AndroidRuntime(450): at android.app.Instrumentation.newActivity(Instrumentation.java:1021)
05-27 06:12:00.734: E/AndroidRuntime(450): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1561)
05-27 06:12:00.734: E/AndroidRuntime(450): ... 11 more
This is my project AACPlayerActivity.java code:
Code:
package com.spoledge.aacplay;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.spoledge.aacdecoder.AACPlayer;
import com.spoledge.aacdecoder.PlayerCallback;
/**
* This is the main activity.
*/
public class AACPlayerActivity extends Activity implements View.OnClickListener, PlayerCallback {
private History history;
private AutoCompleteTextView urlView;
private Button btnPlay;
private Button btnStop;
private TextView txtStatus;
private EditText txtBufAudio;
private EditText txtBufDecode;
private ProgressBar progress;
private Handler uiHandler;
private AACPlayer aacPlayer;
////////////////////////////////////////////////////////////////////////////
// PlayerCallback
////////////////////////////////////////////////////////////////////////////
private boolean playerStarted;
public void playerStarted() {
uiHandler.post( new Runnable() {
public void run() {
txtBufAudio.setEnabled( false );
txtBufDecode.setEnabled( false );
btnPlay.setEnabled( false );
btnStop.setEnabled( true );
txtStatus.setText( R.string.text_buffering );
progress.setProgress( 0 );
progress.setVisibility( View.VISIBLE );
playerStarted = true;
}
});
}
/**
* This method is called periodically by PCMFeed.
*
* @param isPlaying false means that the PCM data are being buffered,
* but the audio is not playing yet
*
* @param audioBufferSizeMs the buffered audio data expressed in milliseconds of playing
* @param audioBufferCapacityMs the total capacity of audio buffer expressed in milliseconds of playing
*/
public void playerPCMFeedBuffer( final boolean isPlaying,
final int audioBufferSizeMs, final int audioBufferCapacityMs ) {
uiHandler.post( new Runnable() {
public void run() {
progress.setProgress( audioBufferSizeMs * progress.getMax() / audioBufferCapacityMs );
if (isPlaying) txtStatus.setText( R.string.text_playing );
}
});
}
public void playerStopped( final int perf ) {
uiHandler.post( new Runnable() {
public void run() {
btnPlay.setEnabled( true );
btnStop.setEnabled( false );
txtBufAudio.setEnabled( true );
txtBufDecode.setEnabled( true );
// txtStatus.setText( R.string.text_stopped );
txtStatus.setText( "" + perf + " %" );
progress.setVisibility( View.INVISIBLE );
playerStarted = false;
}
});
}
public void playerException( final Throwable t) {
uiHandler.post( new Runnable() {
public void run() {
new AlertDialog.Builder( AACPlayerActivity.this )
.setTitle( R.string.text_exception )
.setMessage( t.toString())
.setNeutralButton( R.string.button_close,
new DialogInterface.OnClickListener() {
public void onClick( DialogInterface dialog, int id) {
dialog.cancel();
}
}
)
.show();
txtStatus.setText( R.string.text_stopped );
if (playerStarted) playerStopped( 0 );
}
});
}
////////////////////////////////////////////////////////////////////////////
// OnClickListener
////////////////////////////////////////////////////////////////////////////
/**
* Called when a view has been clicked.
*/
public void onClick( View v ) {
try {
switch (v.getId()) {
case R.id.view_main_button_play: start(); break;
case R.id.view_main_button_stop: stop(); break;
}
}
catch (Exception e) {
Log.e( "AACPlayerActivity", "exc" , e );
}
}
////////////////////////////////////////////////////////////////////////////
// Protected
////////////////////////////////////////////////////////////////////////////
@Override
protected void onCreate( Bundle savedInstanceState ) {
super.onCreate( savedInstanceState );
setContentView( R.layout.main );
btnPlay = (Button) findViewById( R.id.view_main_button_play );
btnStop = (Button) findViewById( R.id.view_main_button_stop );
urlView = (AutoCompleteTextView) findViewById( R.id.view_main_edit_url );
txtStatus = (TextView) findViewById( R.id.view_main_text_status );
txtBufAudio = (EditText) findViewById( R.id.view_main_text_bufaudio );
txtBufDecode = (EditText) findViewById( R.id.view_main_text_bufdecode );
progress = (ProgressBar) findViewById( R.id.view_main_progress );
txtBufAudio.setText( String.valueOf( AACPlayer.DEFAULT_AUDIO_BUFFER_CAPACITY_MS ));
txtBufDecode.setText( String.valueOf( AACPlayer.DEFAULT_DECODE_BUFFER_CAPACITY_MS ));
btnPlay.setOnClickListener( this );
btnStop.setOnClickListener( this );
history = new History( this );
history.read();
if (history.size() == 0 ) {
history.addUrl( "/sdcard/local/cro2-32.aac" );
history.addUrl( "netshow.play.cz:8000/crocb32aac" );
history.addUrl( "62.44.1.26:8000/cro2-128aac" );
history.addUrl( "2483.live.streamtheworld.com:80/KFTZFMAACCMP3" );
history.addUrl( "yourmuze.com:8000/play/paradise/l.aac" );
history.addUrl( "yourmuze.com:8000/play/paradise/m.aac" );
history.addUrl( "yourmuze.com:8000/play/paradise/h.aac" );
}
urlView.setAdapter( history.getArrayAdapter());
uiHandler = new Handler();
}
@Override
protected void onPause() {
super.onPause();
history.write();
}
@Override
protected void onDestroy() {
super.onDestroy();
stop();
}
////////////////////////////////////////////////////////////////////////////
// Private
////////////////////////////////////////////////////////////////////////////
private void start() {
stop();
aacPlayer = new AACPlayer( this, getInt( txtBufAudio ), getInt( txtBufDecode ));
aacPlayer.playAsync( getUrl());
}
private void stop() {
if (aacPlayer != null) {
aacPlayer.stop();
aacPlayer = null;
}
}
private String getUrl() {
String ret = urlView.getText().toString();
history.addUrl( ret );
return ret;
}
private int getInt( EditText et ) {
return Integer.parseInt( et.getText().toString());
}
}
And this is my AndroidManifest.xml:
Code:
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="schemas.android.com/apk/res/android"
package="com.spoledge.aacplay"
android:versionCode="1"
android:versionName="@string/app_version"
>
<uses-permission android:name="android.permission.INTERNET" />
<uses-sdk android:minSdkVersion="10"/>
<application
android:label="@string/app_name"
android:debuggable="true"
>
<activity
android:name="com.spoledge.aacplay.AACPlayerActivity"
android:label="@string/app_name"
android:launchMode="singleTask"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
So can someone help me solve this out? Thanks!
Questions or Problems Should Not Be Posted in the Development Forum
Please Post in the Correct Forums & Read the Forum Rules
Moving to Q&A
Here is your problem:
05-27 06:12:00.734: E/AndroidRuntime(450): Caused by: java.lang.ClassNotFoundException: com.spoledge.aacplay.AACPlayerActivity in loader dalvik.system.PathClassLoader[/data/app/com.spoledge.aacplay-2.apk]
Click to expand...
Click to collapse
are you using any external libraries?
are they exactly in libs directory in your project?
Related
I'm programming a simple Bluetooth client to send and receive text messages throught RFCOMM as a serial port. I had a look at the Android SDK tutorials and did it in the same way: an Activity which calls a thread to make the connection, and once done, another thread to take care of msg reception.
I'm trying to connect to a Parallax EasyBluetooth. Connection works all right between computer and EasyBT, and also between a Java based mobile and the EasyBT. So the problem must be at the code or, I hope not, at the Android mobile bluetooth chip. Anyway it gets on and off, and detects other devices when scanning, so I guess problem is just my coding.
The problem is that the code gets stuck at the connect() method. So let's see if anyone knows why.
The XML for the activity is simple:
Code:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/boton"
android:id="@+id/boton_enviar"
/>
</LinearLayout>
Of course I have added the bluetooth permissions to the Manifiest:
Code:
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
And the code is the following:
Code:
package uniovi.PFC;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
public class PruebaBTActivity extends Activity {
private String TAG = "pruebaBT";
private BluetoothAdapter mBluetoothAdapter;
private Map<String, BluetoothDevice> mArrayAdapter;
private ConnectedThread hiloEscuchas;
private ConnectThread hiloConectando;
private Handler mHandler;
private Button botonEnviar;
private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
private static final int REQUEST_ENABLE_BT = 1;
private static final int MESSAGE_READ = 1;
private byte bytes_enviar[];
private String cmd;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.d(TAG, "On create abriendo");
mArrayAdapter = new HashMap<String, BluetoothDevice>();
botonEnviar = (Button)findViewById(R.id.boton_enviar);
botonEnviar.setEnabled(false);
botonEnviar.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
cmd = "A";
bytes_enviar = cmd.getBytes();
hiloEscuchas.write(bytes_enviar);
}
});
Log.d(TAG, "On create cerrando");
}
@Override
public void onResume() {
super.onResume();
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
Log.d(TAG, "Device does not support Bluetooth");
}
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
// If there are paired devices
if (pairedDevices.size() > 0) {
// Loop through paired devices
for (BluetoothDevice device : pairedDevices) {
// Add the name and address to an array adapter to show in a ListView
mArrayAdapter.put(device.getName(), device);
}
}
BluetoothDevice device = mArrayAdapter.get("EasyBT");
hiloConectando = new ConnectThread(device);
hiloConectando.run();
//while(hiloEscuchas.isConnected()==false);
//botonEnviar.setEnabled(true);
}
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
// Use a temporary object that is later assigned to mmSocket,
// because mmSocket is final
BluetoothSocket tmp = null;
mmDevice = device;
// Get a BluetoothSocket to connect with the given BluetoothDevice
try {
// MY_UUID is the app's UUID string, also used by the server code
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) { }
mmSocket = tmp;
}
public void run() {
// Cancel discovery because it will slow down the connection
mBluetoothAdapter.cancelDiscovery();
try {
// Connect the device through the socket. This will block
// until it succeeds or throws an exception
mmSocket.connect();
} catch (IOException connectException) {
// Unable to connect; close the socket and get out
try {
mmSocket.close();
} catch (IOException closeException) { }
return;
}
// Do work to manage the connection (in a separate thread)
hiloEscuchas = new ConnectedThread(mmSocket);
hiloEscuchas.run();
}
/** Will cancel an in-progress connection, and close the socket */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
private boolean conectado;
public ConnectedThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
conectado = false;
mHandler = new Handler();
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
conectado = true;
}
public boolean isConnected(){
return conectado;
}
public void run() {
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
cmd = "A";
bytes_enviar = cmd.getBytes();
hiloEscuchas.write(bytes_enviar);
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
break;
}
}
}
/* Call this from the main Activity to send data to the remote device */
public void write(byte[] bytes) {
try {
mmOutStream.write(bytes);
} catch (IOException e) { }
}
/* Call this from the main Activity to shutdown the connection */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}
}
There was some code to make a bluetooth scan for devices, but in order to get things simple until it works, I wrote the MAC address manually into a variable. Comments explain this, and also shows where it gets stuck.
Thanks
Can anybody please help me with this? I'm stuck and I need Bluetooth connection working for my thesys
Hello guys. I`m working on a app for listening a online radio station. All works great, but i run into a bump using a spinner. Here is my code:
Code:
package com.hrupin.streamingmedia;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import android.app.Activity;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnBufferingUpdateListener;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import com.hrupin.media.R;
public class StreamingMp3Player extends Activity implements OnClickListener, OnTouchListener, OnCompletionListener, OnBufferingUpdateListener, OnItemSelectedListener{
TextView textMsg, textPrompt;
ImageView imageView;
Spinner spnLocale;
final String textSource = "xxxxxxx.php";
private ImageButton buttonPlayPause;
protected EditText editTextSongURL;
private MediaPlayer mediaPlayer;
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
moveTaskToBack(true);
return true;
}
return super.onKeyDown(keyCode, event);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button btn1 = (Button) findViewById(R.id.btn1);
btn1.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
finish();
System.exit(0);
}
});
imageView = (ImageView) findViewById(R.id.imagine);
textPrompt = (TextView)findViewById(R.id.textprompt);
textMsg = (TextView)findViewById(R.id.textmsg);
textMsg.post( new Runnable(){
public void run(){
URL textUrl;
try {
textUrl = new URL(textSource);
BufferedReader bufferReader = new BufferedReader(new InputStreamReader(textUrl.openStream()));
String StringBuffer;
String stringText = "";
while ((StringBuffer = bufferReader.readLine()) != null) {
stringText += StringBuffer;
}
bufferReader.close();
textMsg.setText(stringText);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
textMsg.setText(e.toString());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
textMsg.setText(e.toString());
}
textMsg.postDelayed(this,(1000*10));
}
});
initView();
spnLocale = (Spinner) findViewById(R.id.spinner);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
this, R.array.planets_array, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spnLocale.setAdapter(adapter);
spnLocale.setOnItemSelectedListener(new StreamingMp3Player());
}
private void initView() {
buttonPlayPause = (ImageButton)findViewById(R.id.ButtonTestPlayPause);
buttonPlayPause.setOnClickListener(this);
editTextSongURL = (EditText)findViewById(R.id.EditTextSongURL);
editTextSongURL.setText("Romantic FM");
mediaPlayer = new MediaPlayer();
mediaPlayer.setOnBufferingUpdateListener(this);
mediaPlayer.setOnCompletionListener(this);
}
public void onClick(View v) {
if(v.getId() == R.id.ButtonTestPlayPause){
try {
mediaPlayer.setDataSource("xxxxxxx:7651");
mediaPlayer.prepare();
} catch (Exception e) {
e.printStackTrace();
}
//mediaFileLengthInMilliseconds = mediaPlayer.getDuration();
if(!mediaPlayer.isPlaying()){
mediaPlayer.start();
//buttonPlayPause.setBackgroundColor(Color.RED);
buttonPlayPause.setImageResource(R.drawable.button_pause);
}else {
mediaPlayer.pause();
buttonPlayPause.setImageResource(R.drawable.button_play);
//System.out.println("Pauza");
}
}
}
public void onItemSelected(AdapterView<?> parent,
View view, int pos, long id) {
if(pos == 1) {
mediaPlayer.pause();
}
}
@SuppressWarnings("rawtypes")
public void onNothingSelected(AdapterView parent) {
// Do nothing.
}
public void onCompletion(MediaPlayer mp) {
buttonPlayPause.setImageResource(R.drawable.button_play);
}
public void onBufferingUpdate(MediaPlayer arg0, int arg1) {
// TODO Auto-generated method stub
}
public boolean onTouch(View arg0, MotionEvent arg1) {
// TODO Auto-generated method stub
return false;
}
}
This next code is supposed to stop mediaplayer from playing if i select a specific value from the spinner options:
Code:
public void onItemSelected(AdapterView<?> parent,
View view, int pos, long id) {
if(pos == 1) {
mediaPlayer.pause();
}
}
public void onNothingSelected(AdapterView parent) {
// Do nothing.
}
But instead of stopping the mediaplayer it crashes. I get this error from logcat:
Code:
05-28 06:34:42.752: E/AndroidRuntime(377): FATAL EXCEPTION: main
05-28 06:34:42.752: E/AndroidRuntime(377): java.lang.NullPointerException
05-28 06:34:42.752: E/AndroidRuntime(377): at com.hrupin.streamingmedia.StreamingMp3Player.onItemSelected(StreamingMp3Player.java:165)
05-28 06:34:42.752: E/AndroidRuntime(377): at android.widget.AdapterView.fireOnSelected(AdapterView.java:871)
05-28 06:34:42.752: E/AndroidRuntime(377): at android.widget.AdapterView.access$200(AdapterView.java:42)
05-28 06:34:42.752: E/AndroidRuntime(377): at android.widget.AdapterView$SelectionNotifier.run(AdapterView.java:837)
05-28 06:34:42.752: E/AndroidRuntime(377): at android.os.Handler.handleCallback(Handler.java:587)
05-28 06:34:42.752: E/AndroidRuntime(377): at android.os.Handler.dispatchMessage(Handler.java:92)
05-28 06:34:42.752: E/AndroidRuntime(377): at android.os.Looper.loop(Looper.java:123)
05-28 06:34:42.752: E/AndroidRuntime(377): at android.app.ActivityThread.main(ActivityThread.java:3683)
05-28 06:34:42.752: E/AndroidRuntime(377): at java.lang.reflect.Method.invokeNative(Native Method)
05-28 06:34:42.752: E/AndroidRuntime(377): at java.lang.reflect.Method.invoke(Method.java:507)
05-28 06:34:42.752: E/AndroidRuntime(377): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
05-28 06:34:42.752: E/AndroidRuntime(377): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
05-28 06:34:42.752: E/AndroidRuntime(377): at dalvik.system.NativeStart.main(Native Method)
So can someone tell me what i'm doing wrong? Thanks!
java.lang.NullPointerException
05-28 06:34:42.752: E/AndroidRuntime(377): at com.hrupin.streamingmedia.StreamingMp3Player.onItemSelected(StreamingMp3Player.java:165)
Click to expand...
Click to collapse
Check this line and see why you have a NULL object, because this is your problem
this is the error(the mediaPlayer.Pause line):
public void onItemSelected(AdapterView<?> parent,
View view, int pos, long id) {
if(pos == 1) {
mediaPlayer.pause();
}
}
but i don`t understand why.
Can somebody please tell me how these bits of code
Code:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
Uri originalUri = data.getData();
selectedImageImageView.setImageURI(originalUri);
selectedImageImageView.setVisibility(View.VISIBLE);
progressDialog.setProgress(0);
progressDialog.show();
new GetImageFileTask(this).execute(imageHelper,
selectedImageImageView);
}
super.onActivityResult(requestCode, resultCode, data);
}
Code:
public static final int GALLERY_KITKAT_INTENT_CALLED = 2;
public static final int GALLERY_INTENT_CALLED = 1;
private final int PREF_WIDTH_IMAGE = 500;
private Activity activity;
public ImageHelper(Activity activity) {
this.activity = activity;
}
public void getImage() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
activity.startActivityForResult(intent, GALLERY_INTENT_CALLED);
} else {
showKitKatGallery();
}
}
private void showKitKatGallery() {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/*");
activity.startActivityForResult(intent, GALLERY_KITKAT_INTENT_CALLED);
}
public File getFileFromImageView(ImageView imageView) throws IOException {
int preferredWidth = PREF_WIDTH_IMAGE;
Bitmap origBitmap = drawableToBitmap(imageView.getDrawable());
int origWidth = origBitmap.getWidth();
int origHeight = origBitmap.getHeight();
int destHeight, destWidth;
if (origWidth <= preferredWidth || origHeight <= preferredWidth) {
destWidth = origWidth;
destHeight = origHeight;
} else {
destWidth = PREF_WIDTH_IMAGE;
destHeight = origHeight / (origWidth / destWidth);
}
File tempFile = new File(activity.getCacheDir(), "temp.png");
tempFile.createNewFile();
Bitmap bitmap = resizeBitmap(origBitmap, destWidth, destHeight);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 0, bos);
byte[] bitmapData = bos.toByteArray();
FileOutputStream fos = new FileOutputStream(tempFile);
fos.write(bitmapData);
fos.close();
return tempFile;
}
public static Bitmap drawableToBitmap(Drawable drawable) {
if (drawable == null) {
return null;
}
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
}
int width = drawable.getIntrinsicWidth();
width = width > 0 ? width : 1;
int height = drawable.getIntrinsicHeight();
height = height > 0 ? height : 1;
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
private Bitmap resizeBitmap(Bitmap inputBitmap, int newWidth, int newHeight) {
return Bitmap.createScaledBitmap(inputBitmap, newWidth, newHeight, true);
}
}
have managed to come up with this error:
Code:
05-15 02:10:01.199: E/AndroidRuntime(17169): FATAL EXCEPTION: main
05-15 02:10:01.199: E/AndroidRuntime(17169): Process: com.simplistic.bloxbackup, PID: 17169
05-15 02:10:01.199: E/AndroidRuntime(17169): java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=2, result=-1, data=Intent { dat=content://com.android.providers.media.documents/document/image:13985 flg=0x43 }} to activity {com.simplistic.bloxbackup/com.simplistic.bloxbackup.activities.GalleryActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ImageView.setImageURI(android.net.Uri)' on a null object reference
05-15 02:10:01.199: E/AndroidRuntime(17169): at android.app.ActivityThread.deliverResults(ActivityThread.java:3637)
05-15 02:10:01.199: E/AndroidRuntime(17169): at android.app.ActivityThread.handleSendResult(ActivityThread.java:3680)
05-15 02:10:01.199: E/AndroidRuntime(17169): at android.app.ActivityThread.access$1300(ActivityThread.java:149)
05-15 02:10:01.199: E/AndroidRuntime(17169): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1373)
05-15 02:10:01.199: E/AndroidRuntime(17169): at android.os.Handler.dispatchMessage(Handler.java:102)
05-15 02:10:01.199: E/AndroidRuntime(17169): at android.os.Looper.loop(Looper.java:211)
05-15 02:10:01.199: E/AndroidRuntime(17169): at android.app.ActivityThread.main(ActivityThread.java:5321)
05-15 02:10:01.199: E/AndroidRuntime(17169): at java.lang.reflect.Method.invoke(Native Method)
05-15 02:10:01.199: E/AndroidRuntime(17169): at java.lang.reflect.Method.invoke(Method.java:372)
05-15 02:10:01.199: E/AndroidRuntime(17169): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1016)
05-15 02:10:01.199: E/AndroidRuntime(17169): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:811)
05-15 02:10:01.199: E/AndroidRuntime(17169): Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ImageView.setImageURI(android.net.Uri)' on a null object reference
05-15 02:10:01.199: E/AndroidRuntime(17169): at com.simplistic.bloxbackup.activities.GalleryActivity.onActivityResult(GalleryActivity.java:101)
05-15 02:10:01.199: E/AndroidRuntime(17169): at android.app.Activity.dispatchActivityResult(Activity.java:6135)
05-15 02:10:01.199: E/AndroidRuntime(17169): at android.app.ActivityThread.deliverResults(ActivityThread.java:3633)
Because i don't know if any of you have seen my thread about my new app "Blox Backup" but the launch has been a big massive flop due this problem.
Now what i don't get is that it was all working as it should before i signed then published it?! I mean i know that apps don't work on every phone but this simply will not work at all no matter the phone!
So can someone please review the code and see where the null pointer is coming from because it shouldn't be coming up as null especially when it didn't before. I have tried to get an answer on Stack but nobody has bothered
So yeah please give me hand because i need this app back on Gplay
Thanks
I'm on my phone right now and have just taken a quick look, but my understanding is that "selectedImageView" is null. You could use something like Eclipse's debugging tool to check in real time where the crash happens and due to what.
So I've been playing around with it and it doesn't crash any more but it'll just finish the intent then do nothing. so nothing is being uploaded...
Code:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == imageHelper.GALLERY_KITKAT_INTENT_CALLED) {
Uri originalUri = data.getData();
selectedImageImageView.setImageURI(originalUri);
selectedImageImageView.setVisibility(View.VISIBLE);
progressDialog.setProgress(0);
progressDialog.show();
new GetImageFileTask(this).execute(imageHelper,
selectedImageImageView);
}else{
if(resultCode == imageHelper.GALLERY_INTENT_CALLED){
Uri originalUri = data.getData();
selectedImageImageView.setImageURI(originalUri);
selectedImageImageView.setVisibility(View.VISIBLE);
progressDialog.setProgress(0);
progressDialog.show();
new GetImageFileTask(this).execute(imageHelper,
selectedImageImageView);
}
}
super.onActivityResult(requestCode, resultCode, data);
}
Code:
public int GALLERY_KITKAT_INTENT_CALLED = 2;
public int GALLERY_INTENT_CALLED = 1;
public ImageHelper(Activity activity) {
this.activity = activity;
}
public void getImage() {
if (Build.VERSION.SDK_INT < 19) {
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
activity.startActivityForResult(intent, 2);
} else {
showKitKatGallery();
}
}
private void showKitKatGallery() {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/*");
activity.startActivityForResult(intent, 1);
}
I also have a feeling this
Code:
public class GetImageFileTask extends AsyncTask<Object, Object, Object> {
private OnGetImageFileListener listener;
public GetImageFileTask(OnGetImageFileListener listener) {
this.listener = listener;
}
@Override
protected Object doInBackground(Object[] params) {
File imageFile = null;
ImageHelper imageHelper = (ImageHelper) params[0];
ImageView imageView = (ImageView) params[1];
try {
imageFile = imageHelper.getFileFromImageView(imageView);
} catch (IOException e) {
e.printStackTrace();
}
return imageFile;
}
@Override
protected void onPostExecute(Object imageFile) {
listener.onGotImageFile((File) imageFile);
}
}
may have something to do with the problem but i could be wrong
X10_minipro said:
I'm on my phone right now and have just taken a quick look, but my understanding is that "selectedImageView" is null. You could use something like Eclipse's debugging tool to check in real time where the crash happens and due to what.
Click to expand...
Click to collapse
I done but it didn't show anything that i didn't already know
Right i give up, I've tried every single "solution" but absolutely nothing works, so i have no idea what's happened but it won't work so this app, unless someone can actually fix it, is going to off the play store
Okay, I'm feeling very very stupid right now, it turns out i forgot i deleted the imageview from the layout but made a rookie mistake and left the code. I'm such a twat.
Introduction
Site Kit is basically used for apps to provide the place related services. This kit provide to search the places with keyword, Find nearby place, place suggestion for user input, Get place details using the unique id.
Features of Huawei Site Kit
Keyword search: Returns a place list based on keywords entered by the user.
Nearby place search: Searches for nearby places based on the current location of the user's device.
Place details: Searches for details about a place.
Search suggestion: Returns a list of place suggestions.
Site Search: Returns a site object.
Development Overview
You need to install Android Studio IDE and I assume that you have prior knowledge of Android application development.
Hardware Requirements
A computer (desktop or laptop) running Windows 10.
Android phone (with the USB cable), which is used for debugging.
Software Requirements
Java JDK 1.8 or later.
Android Studio software or Visual Studio or Code installed.
HMS Core (APK) 4.X or later
Integration steps
Step 1. Huawei developer account and complete identity verification in Huawei developer website, refer to register Huawei ID.
Step 2. Create project in AppGallery Connect
Step 3. Adding HMS Core SDK
Let's start coding
MainActivity.kt
Java:
package com.huawei.hms.knowmyboard.dtse.activity.view
import androidx.navigation.Navigation.findNavController
import androidx.navigation.ui.NavigationUI.setupWithNavController
import com.huawei.hms.knowmyboard.dtse.activity.viewmodel.LoginViewModel
import android.graphics.Bitmap
import com.huawei.hms.mlsdk.langdetect.local.MLLocalLangDetector
import com.huawei.hms.mlsdk.translate.local.MLLocalTranslator
import android.app.ProgressDialog
import androidx.navigation.NavController
import android.os.Bundle
import androidx.databinding.DataBindingUtil
import com.huawei.hms.knowmyboard.dtse.activity.app.MyApplication
import android.content.Intent
import com.huawei.hms.support.account.AccountAuthManager
import android.provider.MediaStore
import com.huawei.hmf.tasks.OnSuccessListener
import com.huawei.hms.mlsdk.langdetect.MLLangDetectorFactory
import com.huawei.hms.mlsdk.langdetect.local.MLLocalLangDetectorSetting
import com.huawei.hmf.tasks.OnFailureListener
import android.content.DialogInterface
import android.net.Uri
import android.util.Log
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProvider
import com.google.android.material.bottomnavigation.BottomNavigationView
import com.huawei.hms.common.ApiException
import com.huawei.hms.knowmyboard.dtse.R
import com.huawei.hms.knowmyboard.dtse.activity.model.UserData
import com.huawei.hms.knowmyboard.dtse.activity.util.Constants
import com.huawei.hms.knowmyboard.dtse.databinding.ActivityMainBinding
import com.huawei.hms.mlsdk.MLAnalyzerFactory
import com.huawei.hms.mlsdk.common.MLApplication
import com.huawei.hms.mlsdk.common.MLFrame
import com.huawei.hms.mlsdk.translate.local.MLLocalTranslateSetting
import com.huawei.hms.mlsdk.translate.MLTranslatorFactory
import com.huawei.hms.mlsdk.model.download.MLModelDownloadStrategy
import com.huawei.hms.mlsdk.model.download.MLModelDownloadListener
import com.huawei.hms.mlsdk.text.MLLocalTextSetting
import com.huawei.hms.mlsdk.text.MLText
import com.huawei.hms.mlsdk.text.MLTextAnalyzer
import java.io.IOException
import java.lang.Exception
import java.util.ArrayList
class MainActivity() : AppCompatActivity() {
var loginViewModel: LoginViewModel? = null
private var mTextAnalyzer: MLTextAnalyzer? = null
var imagePath: Uri? = null
var bitmap: Bitmap? = null
var result = ArrayList<String>()
var myLocalLangDetector: MLLocalLangDetector? = null
var myLocalTranslator: MLLocalTranslator? = null
var textRecognized: String? = null
var progressDialog: ProgressDialog? = null
var navController: NavController? = null
var activityMainBinding: ActivityMainBinding? = null
var bottomNavigationView: BottomNavigationView? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activityMainBinding =
DataBindingUtil.setContentView([email protected], R.layout.activity_main)
loginViewModel = ViewModelProvider([email protected]).get(
LoginViewModel::class.java
)
navController = findNavController([email protected], R.id.nav_host_fragment)
MyApplication.activity = this
progressDialog = ProgressDialog(this)
progressDialog!!.setCancelable(false)
bottomNavigationView = activityMainBinding!!.bottomNavigation
setupWithNavController(bottomNavigationView!!, navController!!)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
// Process the authorization result to obtain the authorization code from AuthAccount.
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 1234) {
Log.e("TAG", " Result can be pulled")
}
if (requestCode == 8888) {
val authAccountTask = AccountAuthManager.parseAuthResultFromIntent(data)
if (authAccountTask.isSuccessful) {
// The sign-in is successful, and the user's ID information and authorization code are obtained.
val authAccount = authAccountTask.result
val userData = UserData()
userData.accessToken = authAccount.accessToken
userData.countryCode = authAccount.countryCode
userData.displayName = authAccount.displayName
userData.email = authAccount.email
userData.familyName = authAccount.familyName
userData.givenName = authAccount.givenName
userData.idToken = authAccount.idToken
userData.openId = authAccount.openId
userData.uid = authAccount.uid
userData.photoUriString = authAccount.avatarUri.toString()
userData.unionId = authAccount.unionId
loginViewModel = ViewModelProvider([email protected]).get(
LoginViewModel::class.java
)
loginViewModel!!.sendData(authAccount.displayName)
} else {
// The sign-in failed.
Log.e(
"TAG",
"sign in failed:" + (authAccountTask.exception as ApiException).statusCode
)
}
}
if ((requestCode == 2323) && (resultCode == RESULT_OK) && (data != null)) {
progressDialog!!.setMessage("Initializing text detection..")
progressDialog!!.show()
imagePath = data.data
try {
bitmap = MediaStore.Images.Media.getBitmap(this.contentResolver, imagePath)
asyncAnalyzeText(bitmap)
} catch (e: IOException) {
e.printStackTrace()
Log.e("TAG", " BITMAP ERROR")
}
}
if ((requestCode == 2424) && (resultCode == RESULT_OK) && (data != null)) {
progressDialog!!.setMessage("Initializing text detection..")
progressDialog!!.show()
try {
bitmap = data.extras!!["data"] as Bitmap?
asyncAnalyzeText(bitmap)
} catch (e: Exception) {
e.printStackTrace()
Log.e("TAG", " BITMAP ERROR")
}
}
}
private fun asyncAnalyzeText(bitmap: Bitmap?) {
if (mTextAnalyzer == null) {
createMLTextAnalyzer()
}
val frame = MLFrame.fromBitmap(bitmap)
val task = mTextAnalyzer!!.asyncAnalyseFrame(frame)
task.addOnSuccessListener(object : OnSuccessListener<MLText> {
override fun onSuccess(text: MLText) {
progressDialog!!.setMessage("Initializing language detection..")
textRecognized = text.stringValue.trim { it <= ' ' }
if (!textRecognized!!.isEmpty()) {
// Create a local language detector.
val factory = MLLangDetectorFactory.getInstance()
val setting =
MLLocalLangDetectorSetting.Factory() // Set the minimum confidence threshold for language detection.
.setTrustedThreshold(0.01f)
.create()
myLocalLangDetector = factory.getLocalLangDetector(setting)
val firstBestDetectTask = myLocalLangDetector!!.firstBestDetect(textRecognized)
firstBestDetectTask.addOnSuccessListener(OnSuccessListener { languageDetected ->
progressDialog!!.setMessage("Initializing text translation..")
// Processing logic for detection success.
textTranslate(languageDetected, textRecognized!!, bitmap)
}).addOnFailureListener(object : OnFailureListener {
override fun onFailure(e: Exception) {
// Processing logic for detection failure.
Log.e("TAG", "Lang detect error:" + e.message)
}
})
} else {
progressDialog!!.dismiss()
showErrorDialog("Failed to recognize text.")
}
}
}).addOnFailureListener(object : OnFailureListener {
override fun onFailure(e: Exception) {
Log.e("TAG", "#==>" + e.message)
}
})
}
private fun showErrorDialog(msg: String) {
val alertDialog = AlertDialog.Builder(this).create()
alertDialog.setTitle("Error")
alertDialog.setMessage(msg)
alertDialog.setButton(
AlertDialog.BUTTON_POSITIVE,
"OK",
object : DialogInterface.OnClickListener {
override fun onClick(dialog: DialogInterface, which: Int) {
dialog.dismiss()
}
})
alertDialog.show()
}
private fun textTranslate(languageDetected: String, textRecognized: String, uri: Bitmap?) {
MLApplication.initialize(application)
MLApplication.getInstance().apiKey = Constants.API_KEY
// Create an offline translator.
val setting =
MLLocalTranslateSetting.Factory() // Set the source language code. The ISO 639-1 standard is used. This parameter is mandatory. If this parameter is not set, an error may occur.
.setSourceLangCode(languageDetected) // Set the target language code. The ISO 639-1 standard is used. This parameter is mandatory. If this parameter is not set, an error may occur.
.setTargetLangCode("en")
.create()
myLocalTranslator = MLTranslatorFactory.getInstance().getLocalTranslator(setting)
// Set the model download policy.
val downloadStrategy = MLModelDownloadStrategy.Factory()
.needWifi() // It is recommended that you download the package in a Wi-Fi environment.
.create()
// Create a download progress listener.
val modelDownloadListener: MLModelDownloadListener = object : MLModelDownloadListener {
override fun onProcess(alreadyDownLength: Long, totalLength: Long) {
runOnUiThread(object : Runnable {
override fun run() {
// Display the download progress or perform other operations.
}
})
}
}
myLocalTranslator!!.preparedModel(downloadStrategy, modelDownloadListener)
.addOnSuccessListener(object : OnSuccessListener<Void?> {
override fun onSuccess(aVoid: Void?) {
// Called when the model package is successfully downloaded.
// input is a string of less than 5000 characters.
val task = myLocalTranslator!!.asyncTranslate(textRecognized)
// Before translation, ensure that the models have been successfully downloaded.
task.addOnSuccessListener(object : OnSuccessListener<String> {
override fun onSuccess(translated: String) {
// Processing logic for detection success.
result.clear()
result.add(languageDetected.trim { it <= ' ' })
result.add(textRecognized.trim { it <= ' ' })
result.add(translated.trim { it <= ' ' })
loginViewModel!!.setImage(uri!!)
loginViewModel!!.setTextRecongnized(result)
progressDialog!!.dismiss()
}
}).addOnFailureListener(object : OnFailureListener {
override fun onFailure(e: Exception) {
// Processing logic for detection failure.
progressDialog!!.dismiss()
}
})
}
}).addOnFailureListener(object : OnFailureListener {
override fun onFailure(e: Exception) {
// Called when the model package fails to be downloaded.
progressDialog!!.dismiss()
}
})
}
private fun createMLTextAnalyzer() {
val setting = MLLocalTextSetting.Factory()
.setOCRMode(MLLocalTextSetting.OCR_DETECT_MODE)
.create()
mTextAnalyzer = MLAnalyzerFactory.getInstance().getLocalTextAnalyzer(setting)
}
override fun onStop() {
if (myLocalLangDetector != null) {
myLocalLangDetector!!.stop()
}
if (myLocalTranslator != null) {
myLocalTranslator!!.stop()
}
if (progressDialog != null) {
progressDialog!!.dismiss()
}
super.onStop()
}
companion object {
var TAG = "TAG"
}
}
LoginViewModel.kt
Java:
package com.huawei.hms.knowmyboard.dtse.activity.viewmodel
import android.app.Application
import com.huawei.hms.support.account.service.AccountAuthService
import android.graphics.Bitmap
import com.huawei.hms.location.LocationResult
import com.huawei.hms.site.api.model.Site
import android.widget.Toast
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.huawei.hms.common.ApiException
import com.huawei.hms.knowmyboard.dtse.R
import com.huawei.hms.support.account.request.AccountAuthParams
import com.huawei.hms.support.account.request.AccountAuthParamsHelper
import com.huawei.hms.support.account.AccountAuthManager
import com.huawei.hms.knowmyboard.dtse.activity.app.MyApplication
import java.util.ArrayList
class LoginViewModel(application: Application) : AndroidViewModel(application) {
var service: AccountAuthService? = null
val message = MutableLiveData<String>()
val textRecongnized = MutableLiveData<ArrayList<String>>()
val imagePath = MutableLiveData<Bitmap>()
val locationResult = MutableLiveData<LocationResult>()
val siteSelected = MutableLiveData<Site>()
fun getSiteSelected(): LiveData<Site> {
return siteSelected
}
fun setSiteSelected(siteSelected: Site) {
this.siteSelected.value = siteSelected
}
fun sendData(msg: String) {
message.value = msg
}
fun getMessage(): LiveData<String> {
return message
}
fun setImage(imagePath: Bitmap) {
this.imagePath.value = imagePath
}
fun setLocationResult(locationResult: LocationResult) {
this.locationResult.value = locationResult
}
fun setTextRecongnized(textRecongnized: ArrayList<String>) {
this.textRecongnized.value = textRecongnized
}
fun logoutHuaweiID() {
if (service != null) {
service!!.signOut()
sendData("KnowMyBoard")
Toast.makeText(getApplication(), "You are logged out from Huawei ID", Toast.LENGTH_LONG)
.show()
}
}
fun loginClicked() {
val authParams =
AccountAuthParamsHelper(AccountAuthParams.DEFAULT_AUTH_REQUEST_PARAM).setAuthorizationCode()
.createParams()
service = AccountAuthManager.getService(MyApplication.activity, authParams)
MyApplication.activity!!.startActivityForResult(service!!.signInIntent, 8888)
}
fun cancelAuthorization() {
if (service != null) {
// service indicates the AccountAuthService instance generated using the getService method during the sign-in authorization.
service!!.cancelAuthorization().addOnCompleteListener { task ->
if (task.isSuccessful) {
// Processing after a successful authorization cancellation.
sendData(getApplication<Application>().resources.getResourceName(R.string.app_name))
Toast.makeText(getApplication(), "Cancelled authorization", Toast.LENGTH_LONG)
.show()
} else {
// Handle the exception.
val exception = task.exception
if (exception is ApiException) {
val statusCode = exception.statusCode
Toast.makeText(
getApplication(),
"Failed to cancel authorization. status code $statusCode",
Toast.LENGTH_LONG
).show()
}
}
}
} else {
Toast.makeText(getApplication(), "Login required", Toast.LENGTH_LONG).show()
}
}
}
SearchFragment.kt
Java:
package com.huawei.hms.knowmyboard.dtse.activity.fragments
import androidx.navigation.Navigation.findNavController
import com.huawei.hms.knowmyboard.dtse.activity.viewmodel.LoginViewModel
import androidx.navigation.NavController
import com.huawei.hms.site.api.SearchService
import com.huawei.hms.knowmyboard.dtse.activity.adapter.SitesAdapter
import com.huawei.hms.site.api.model.Site
import com.huawei.hms.location.LocationResult
import com.huawei.hms.knowmyboard.dtse.activity.intefaces.ItemClickListener
import android.view.WindowManager
import android.view.LayoutInflater
import android.view.ViewGroup
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.appcompat.widget.SearchView
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.huawei.hms.knowmyboard.dtse.R
import com.huawei.hms.knowmyboard.dtse.activity.util.Constants
import com.huawei.hms.knowmyboard.dtse.databinding.FragmentSearchBinding
import com.huawei.hms.site.api.SearchServiceFactory
import com.huawei.hms.site.api.model.TextSearchRequest
import com.huawei.hms.site.api.model.Coordinate
import com.huawei.hms.site.api.SearchResultListener
import com.huawei.hms.site.api.model.TextSearchResponse
import com.huawei.hms.site.api.model.SearchStatus
import com.huawei.hms.site.api.model.NearbySearchRequest
import com.huawei.hms.site.api.model.HwLocationType
import com.huawei.hms.site.api.model.NearbySearchResponse
import java.io.UnsupportedEncodingException
import java.lang.Exception
import java.net.URLEncoder
import java.util.ArrayList
class SearchFragment : Fragment() {
var binding: FragmentSearchBinding? = null
var loginViewModel: LoginViewModel? = null
//View view;
var navController: NavController? = null
private var searchService: SearchService? = null
var adapter: SitesAdapter? = null
var siteArrayList = ArrayList<Site>()
var locationResult: LocationResult? = null
/* var siteClicklistener = ItemClickListener { vh, site, pos ->
requireActivity().window.setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN
)
loginViewModel!!.setSiteSelected(site)
navController!!.navigate(R.id.loginFragment)
}*/
var siteClicklistener = object : ItemClickListener{
override fun onItemClicked(vh: RecyclerView.ViewHolder?, item: Site?, pos: Int) {
requireActivity().window.setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN
)
loginViewModel!!.setSiteSelected(item!!)
navController!!.navigate(R.id.loginFragment)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
requireActivity().window.setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE
)
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_search, container, false)
loginViewModel = ViewModelProvider(requireActivity()).get(
LoginViewModel::class.java
)
val searchView = binding!!.edSearch
val recyclerView = binding!!.suggestionRv
navController = findNavController(requireActivity(), R.id.nav_host_fragment)
searchView.isFocusable = true
searchView.onActionViewExpanded()
adapter = SitesAdapter(siteArrayList, context, siteClicklistener)
recyclerView.adapter = adapter
recyclerView.layoutManager = LinearLayoutManager(context)
recyclerView.setHasFixedSize(true)
loginViewModel!!.locationResult.observeForever { locationResult1 ->
locationResult = locationResult1
}
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
return false
}
override fun onQueryTextChange(newText: String): Boolean {
if (newText.length > 4) {
nearByPlacesSearch(newText)
}
return false
}
})
return binding!!.root
}
fun keywordSearch(search: String?) {
try {
val key = URLEncoder.encode(Constants.API_KEY, "UTF-8")
// Instantiate the SearchService object.
searchService = SearchServiceFactory.create(context, key)
// Create a request body.
val request = TextSearchRequest()
request.query = search
if (locationResult != null) {
val location = Coordinate(
locationResult!!.lastHWLocation.latitude,
locationResult!!.lastHWLocation.longitude
)
request.location = location
}
request.radius = 1000
//request.setHwPoiType(HwLocationType.HOTEL_MOTEL);
request.countryCode = "IN"
request.language = "en"
request.pageIndex = 1
request.pageSize = 5
request.isChildren = false
// request.setCountries(Arrays.asList("en", "fr", "cn", "de", "ko","in"));
// Create a search result listener.
val resultListener: SearchResultListener<TextSearchResponse?> =
object : SearchResultListener<TextSearchResponse?> {
// Return search results upon a successful search.
override fun onSearchResult(results: TextSearchResponse?) {
if (results == null || results.totalCount <= 0) {
return
}
val sites = results.sites
if (sites == null || sites.size == 0) {
return
}
siteArrayList.clear()
for (site in sites) {
siteArrayList.add(site)
}
siteArrayList.addAll(sites)
adapter!!.notifyDataSetChanged()
}
// Return the result code and description upon a search exception.
override fun onSearchError(status: SearchStatus) {
Log.i("TAG", "Error : " + status.errorCode + " " + status.errorMessage)
}
}
// Call the keyword search API.
searchService!!.textSearch(request, resultListener)
} catch (e: UnsupportedEncodingException) {
e.printStackTrace()
}
}
fun nearByPlacesSearch(newText: String?) {
try {
val key = URLEncoder.encode(Constants.API_KEY, "UTF-8")
// Instantiate the SearchService object.
searchService = SearchServiceFactory.create(context, key)
// Create a request body.
val request = NearbySearchRequest()
if (locationResult != null) {
val location = Coordinate(
locationResult!!.lastHWLocation.latitude,
locationResult!!.lastHWLocation.longitude
)
request.location = location
}
request.query = newText
request.radius = 1000
request.hwPoiType = HwLocationType.ADDRESS
request.language = "en"
request.pageIndex = 1
request.pageSize = 5
request.strictBounds = false
// Create a search result listener.
val resultListener: SearchResultListener<NearbySearchResponse?> =
object : SearchResultListener<NearbySearchResponse?> {
// Return search results upon a successful search.
override fun onSearchResult(results: NearbySearchResponse?) {
if (results == null || results.totalCount <= 0) {
return
}
val sites = results.sites
if (sites == null || sites.size == 0) {
return
}
siteArrayList.clear()
for (site in sites) {
siteArrayList.add(site)
}
siteArrayList.addAll(sites)
adapter!!.notifyDataSetChanged()
}
// Return the result code and description upon a search exception.
override fun onSearchError(status: SearchStatus) {
Log.i("TAG", "Error : " + status.errorCode + " " + status.errorMessage)
}
}
// Call the nearby place search API.
searchService!!.nearbySearch(request, resultListener)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
RequestLocationData.kt
Java:
package com.huawei.hms.knowmyboard.dtse.activity.util
import android.Manifest
import com.huawei.hms.knowmyboard.dtse.activity.viewmodel.LoginViewModel
import android.app.Activity
import android.content.Context
import android.os.Build
import android.content.pm.PackageManager
import android.os.Looper
import android.location.Geocoder
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.core.app.ActivityCompat
import androidx.fragment.app.FragmentActivity
import com.huawei.hms.location.*
import java.io.IOException
import java.lang.StringBuilder
import java.util.*
class RequestLocationData(
context: Context?,
activity: FragmentActivity?,
loginViewModel: LoginViewModel?
) {
private var settingsClient: SettingsClient? = null
private var isLocationSettingSuccess = 0
private var myLocationRequest: LocationRequest? = null
// Define a fusedLocationProviderClient object.
private var fusedLocationProviderClient: FusedLocationProviderClient? = null
private var myLocationCallback: LocationCallback? = null
var context: Context? = null
var activity: Activity? = null
private var locationResult: LocationResult? = null
var loginViewModel: LoginViewModel? = null
fun initFusionLocationProviderClint() {
// Instantiate the fusedLocationProviderClient object.
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(activity)
this.settingsClient = LocationServices.getSettingsClient(activity)
}
fun checkDeviceLocationSettings() {
val builder = LocationSettingsRequest.Builder()
myLocationRequest = LocationRequest()
builder.addLocationRequest(myLocationRequest)
val locationSettingsRequest = builder.build()
// Check the device location settings.
settingsClient!!.checkLocationSettings(locationSettingsRequest) // Define the listener for success in calling the API for checking device location settings.
.addOnSuccessListener { locationSettingsResponse: LocationSettingsResponse ->
val locationSettingsStates = locationSettingsResponse.locationSettingsStates
val stringBuilder = StringBuilder()
// Check whether the location function is enabled.
stringBuilder.append(",\nisLocationUsable=")
.append(locationSettingsStates.isLocationUsable)
// Check whether HMS Core (APK) is available.
stringBuilder.append(",\nisHMSLocationUsable=")
.append(locationSettingsStates.isHMSLocationUsable)
Log.i(TAG, "checkLocationSetting onComplete:$stringBuilder")
// Set the location type.
myLocationRequest!!.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
// Set the number of location updates to 1.
myLocationRequest!!.numUpdates = 1
isLocationSettingSuccess = 1
} // Define callback for failure in checking the device location settings.
.addOnFailureListener { e -> Log.i(TAG, "checkLocationSetting onFailure:" + e.message) }
}
@RequiresApi(Build.VERSION_CODES.S)
fun checkPermission() {
// Dynamically apply for required permissions if the API level is 28 or lower.
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
Log.i(TAG, "android sdk <= 28 Q")
if (ActivityCompat.checkSelfPermission(
context!!,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(
context!!,
Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
val strings = arrayOf(
Manifest.permission.CAMERA,
Manifest.permission.MANAGE_MEDIA,
Manifest.permission.MEDIA_CONTENT_CONTROL,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
)
ActivityCompat.requestPermissions(activity!!, strings, 1)
}
} else {
// Dynamically apply for the android.permission.ACCESS_BACKGROUND_LOCATION permission in addition to the preceding permissions if the API level is higher than 28.
if (ActivityCompat.checkSelfPermission(
activity!!,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
context!!,
Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
context!!,
"android.permission.ACCESS_BACKGROUND_LOCATION"
) != PackageManager.PERMISSION_GRANTED
) {
val strings = arrayOf(
Manifest.permission.CAMERA,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.MEDIA_CONTENT_CONTROL,
Manifest.permission.MANAGE_MEDIA,
"android.permission.ACCESS_BACKGROUND_LOCATION"
)
ActivityCompat.requestPermissions(activity!!, strings, 2)
}
}
}
fun refreshLocation(): LocationResult? {
Log.d(TAG, "Refreshing location")
if (isLocationSettingSuccess == 1) {
myLocationCallback = object : LocationCallback() {
private var locationResult: LocationResult? = null
override fun onLocationResult(locationResult: LocationResult) {
if (locationResult != null) {
// Gson gson = new Gson();
//Log.d(TAG, " Location data :" + locationResult.getLastLocation().getLatitude() + " : " + locationResult.getLastLocation().getLongitude());
//Log.d(TAG, " Location data :" + gson.toJson(locationResult.getLastHWLocation()));
//Log.d(TAG, " Location data :" + locationResult.getLastHWLocation().getCountryName());
Log.d(TAG, " Location data :" + locationResult.lastHWLocation.latitude)
Log.d(TAG, " Location data :" + locationResult.lastHWLocation.longitude)
// binding.textDetected.setText("Latitude " + locationResult.getLastHWLocation().getLatitude() + " Longitude " + locationResult.getLastHWLocation().getLongitude());
//getGeoCoderValues(locationResult.getLastHWLocation().getLatitude(),locationResult.getLastHWLocation().getLongitude());
this.locationResult = locationResult
loginViewModel!!.setLocationResult(locationResult)
}
}
}
fusedLocationProviderClient!!.requestLocationUpdates(
myLocationRequest,
myLocationCallback,
Looper.getMainLooper()
)
} else {
Log.d(TAG, "Failed to get location settings")
}
return locationResult
}
fun disableLocationData() {
fusedLocationProviderClient!!.disableBackgroundLocation()
fusedLocationProviderClient!!.removeLocationUpdates(myLocationCallback)
}
private fun getGeoCoderValues(latitude: Double, longitude: Double) {
getAddress(context, latitude, longitude)
/* Geocoder geocoder;
List<Address> addresses;
Locale locale = new Locale("en", "IN");
geocoder = new Geocoder(getContext(), locale);
try {
addresses = geocoder.getFromLocation(latitude, longitude, 1); // Here 1 represent max location result to returned, by documents it recommended 1 to 5
Gson gson=new Gson();
Log.d(TAG,"Geo coder :"+gson.toJson(addresses));
String address = addresses.get(0).getAddressLine(0); // If any additional address line present than only, check with max available address lines by getMaxAddressLineIndex()
String city = addresses.get(0).getLocality();
String state = addresses.get(0).getAdminArea();
String country = addresses.get(0).getCountryName();
String postalCode = addresses.get(0).getPostalCode();
String knownName = addresses.get(0).getFeatureName();
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG,"Error while fetching Geo coder :"+e.getMessage());
}*/
/* Locale locale = new Locale("en", "IN");
GeocoderService geocoderService =
LocationServices.getGeocoderService(getActivity().getBaseContext(), locale);
// Request reverse geocoding.
GetFromLocationRequest getFromLocationRequest = new GetFromLocationRequest(latitude, longitude, 5);
// Initiate reverse geocoding.
geocoderService.getFromLocation(getFromLocationRequest)
.addOnSuccessListener(hwLocation -> {
Gson gson=new Gson();
Log.d(TAG,"Geo coder :"+gson.toJson(hwLocation));
})
.addOnFailureListener(e -> {
Log.e(TAG,"Error while fetching Geo coder :"+e.getMessage());
});*/
}
companion object {
var TAG = "TAG"
fun getAddress(context: Context?, LATITUDE: Double, LONGITUDE: Double) {
//Set Address
try {
val geocoder = Geocoder(context, Locale.getDefault())
val addresses = geocoder.getFromLocation(LATITUDE, LONGITUDE, 1)
if (addresses != null && addresses.size > 0) {
val address =
addresses[0].getAddressLine(0) // If any additional address line present than only, check with max available address lines by getMaxAddressLineIndex()
val city = addresses[0].locality
val state = addresses[0].adminArea
val country = addresses[0].countryName
val postalCode = addresses[0].postalCode
val knownName = addresses[0].featureName // Only if available else return NULL
Log.d(TAG, "getAddress: address$address")
Log.d(TAG, "getAddress: city$city")
Log.d(TAG, "getAddress: state$state")
Log.d(TAG, "getAddress: postalCode$postalCode")
Log.d(TAG, "getAddress: knownName$knownName")
}
} catch (e: IOException) {
e.printStackTrace()
Log.e(TAG, "Error while fetching Geo coder :" + e.message)
}
}
}
init {
[email protected] = context
[email protected] = activity
[email protected] = loginViewModel
}
}
navigation_graph.xml
XML:
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/navigation_graph"
app:startDestination="@id/loginFragment">
<fragment
android:id="@+id/loginFragment"
android:name="com.huawei.hms.knowmyboard.dtse.activity.fragments.LoginFragment"
android:label="LoginFragment"/>
<fragment
android:id="@+id/mainFragment"
android:name="com.huawei.hms.knowmyboard.dtse.activity.fragments.MainFragment"
android:label="MainFragment"/>
<fragment
android:id="@+id/searchFragment"
android:name="com.huawei.hms.knowmyboard.dtse.activity.fragments.SearchFragment"
android:label="fragment_search"
tools:layout="@layout/fragment_search" />
</navigation>
bottom_navigation_menu.xml
XML:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/searchFragment"
android:icon="@android:drawable/ic_menu_search"
android:title="@string/search" />
<item
android:id="@+id/loginFragment"
android:icon="@android:drawable/ic_menu_agenda"
android:title="Home" />
<item
android:id="@+id/mainFragment"
app:showAsAction="always"
android:icon="@android:drawable/ic_menu_gallery"
android:title="Gallery" />
</menu>
Result
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Tricks and Tips
Makes sure that agconnect-services.json file added.
Make sure required dependencies are added
Make sure that service is enabled in AGC
Enable data binding in gradle.build file
Make sure bottom navigation id's should be same as fragment id's in navigation graph
Conclusion
In this article, we have learnt how to integrate Huawei Site Kit, Map kit, Location kit in Android application KnowMyBoard. Hoping that the Map kit capabilities are helpful to you as well, like this sample, you can make use of Site kit as per your requirement.
Reference
Map Kit – Training video
Site Kit – Training video
Hi,
I'm new in this forum so I don't know if i'm in the correct section...
I created this class named BLEConnection becuase i'm tring to connect to a esp32 via BLE but i'm having some problem in the connection part... the class:
Java:
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.Context;
import android.os.ParcelUuid;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class BLEConnection {
private BluetoothAdapter mBluetoothAdapter;
private BluetoothLeScanner mBluetoothLeScanner;
private String mTargetDeviceAddress;
private boolean mScanning;
private BLEConnectionListener mListener;
private BluetoothGatt mBluetoothGatt;
private Context mContext;
private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
// This callback is invoked when the connection state changes, e.g. from disconnected to connected.
if (newState == BluetoothProfile.STATE_CONNECTED) {
Log.e("bleee", "connected ");
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.e("bleee", "disconected");
}
}
};
private ScanCallback mScanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) { // This callback is invoked when a BLE advertisement is found.
Log.e("bleee", "scan result");
BluetoothDevice device = result.getDevice();
if (device.getAddress().equals(mTargetDeviceAddress)) {
Log.e("bleee", "device found 1");
mBluetoothLeScanner.stopScan(mScanCallback);
mScanning = false;
mListener.onDeviceFound(device);
}
}
@Override
public void onBatchScanResults(List<ScanResult> results) { // This callback is invoked when multiple BLE advertisements are found at once.
Log.e("bleee", "scan result multiple");
for (ScanResult result : results) {
BluetoothDevice device = result.getDevice();
if (device.getAddress().equals(mTargetDeviceAddress)) {
Log.e("bleee", "batch scan multiple");
mBluetoothLeScanner.stopScan(mScanCallback);
mScanning = false;
mListener.onDeviceFound(device);
break;
}
}
}
@Override
public void onScanFailed(int errorCode) {
Log.e("bleee", "scan failed 1");
mScanning = false;
mListener.onScanFailed(errorCode);
}
};
public BLEConnection(Context context, String targetDeviceAddress, BLEConnectionListener listener) {
mTargetDeviceAddress = targetDeviceAddress;
mListener = listener;
BluetoothManager bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
}
public void startScan() {
Log.e("bleee", "starting scan..................");
if (mScanning) {
return;
}
List<ScanFilter> filters = new ArrayList<>();
ScanFilter filter = new ScanFilter.Builder()
.setDeviceAddress(mTargetDeviceAddress)
.build();
filters.add(filter);
ScanSettings settings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)
.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
.setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE)
.setNumOfMatches(ScanSettings.MATCH_NUM_ONE_ADVERTISEMENT)
.setReportDelay(0L)
.build();
mBluetoothLeScanner.startScan(filters, settings, mScanCallback);
mScanning = true;
Log.e("bleee", "finished?");
}
public void stopScan() {
Log.e("bleee", "something stopped the scan");
if (mScanning) {
mBluetoothLeScanner.stopScan(mScanCallback);
mScanning = false;
}
}
public void writeMessage(byte[] message) {
Log.e("bleee", "writing message...............");
if (mBluetoothGatt == null) {
return;
}
BluetoothGattService service = mBluetoothGatt.getService(UUID.fromString("4fafc201-1fb5-459e-8fcc-c5c9c331914b"));
if (service == null) {
return;
}
BluetoothGattCharacteristic characteristic = service.getCharacteristic(UUID.fromString("beb5483e-36e1-4688-b7f5-ea07361b26a8"));
if (characteristic == null) {
return;
}
characteristic.setValue(message);
mBluetoothGatt.writeCharacteristic(characteristic);
}
public interface BLEConnectionListener {
void onDeviceFound(BluetoothDevice device);
void onScanFailed(int errorCode);
}
public void connectToDevice(BluetoothDevice device) {
Log.e("bleee", "Trying connecting");
mBluetoothGatt = device.connectGatt(mContext, false, mGattCallback);
}
public void disconnectFromDevice() {
if (mBluetoothGatt != null) {
mBluetoothGatt.disconnect();
mBluetoothGatt.close();
mBluetoothGatt = null;
}
}
}
please ignore that android studio thinks that some code is an error (because could not be safe and could crash if Bluetooth is not enable, but i'll skip for now this).
So now, I have a service that is this (eliminated useless method for my problem):
Java:
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.IBinder;
import android.util.Log;
//import com.welie.blessed.*;
public class SendNotifyService extends Service implements BLEConnection.BLEConnectionListener {
private volatile boolean shouldStopThread;
private volatile boolean oksend = false;
private String ESP32_MAC_ADDRESS = "84:F7:03:68:06:52";
private BLEConnection mBLEConnection;
public SendNotifyService() {}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
shouldStopThread = false;
mBLEConnection = new BLEConnection(this, ESP32_MAC_ADDRESS, this);
// Start scanning for the device
mBLEConnection.startScan();
new Thread(new Runnable() {
@Override
public void run() {
while (!shouldStopThread) {
//-----------------------------------------------------------------------------------------------------
if(oksend == true){
byte[] message = "Hello, device!".getBytes();
mBLEConnection.writeMessage(message);
}
Log.e("Service Ard_OS", "Service is running...");
Log.e("Service Ard_OS", mac);
pause(4000);
//-----------------------------------------------------------------------------------------------------
}}
public void pause(int millis){ try { Thread.sleep(millis); } catch (InterruptedException e) { e.printStackTrace(); } }
}).start();
return START_STICKY;
}
@Override
public void onDeviceFound(BluetoothDevice device) {
Log.e("bleee", "device found 2");
oksend = true;
mBLEConnection.connectToDevice(device);
}
@Override
public void onScanFailed(int errorCode) {
Log.e("bleee", "scan failed, i think...");
}
}
Now it comes the problem:
Obviously I'm using a real phone (samsung galaxy a20e) that runs API 30.
When I start the Service in the LOGCAT using the filter "bleee" i can only see theese two debug message:
------------------ PROCESS STARTED (9353) for package com.example.ard_os ------------------
2023-01-03 22:52:02.993 9353-9353 bleee com.example.ard_os E starting scan..................
2023-01-03 22:52:03.012 9353-9353 bleee com.example.ard_os E finished?
Click to expand...
Click to collapse
So the problem is that i don't get nothing else, not in the BluetoothGattCallback and not even in the ScanCallback. It doesn't connect to the device... If I was not clear about something I will answer!
Thanks to everyone.
I fixed, while this functions were called in a Service I needed the ACCESS_BACKGROUND_LOCATION to scan... So my manifest is now:
<uses-permission-sdk-23 android:name="android.permission.ACCESS_FINE_LOCATION" tools:node="remove" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission-sdk-23 android:name="android.permission.ACCESS_COARSE_LOCATION" tools:node="remove" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" android:maxSdkVersion="30" />
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
<uses-feature android:name="android.hardware.bluetooth" android:required="true"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
rember that some of these permissions needs the user approvment, so you need the Run Time Permission.
table with needed permissions to scan:
18 to 22 (No runtime permissions needed)
23 to 28 One of below:
- android.permission.ACCESS_COARSE_LOCATION
- android.permission.ACCESS_FINE_LOCATION
29 to 30 - android.permission.ACCESS_FINE_LOCATION
- android.permission.ACCESS_BACKGROUND_LOCATION*
31 to current - android.permission.BLUETOOTH_SCAN
- android.permission.ACCESS_FINE_LOCATION**
* Needed if scan is performed in background
** Only needed if you want to obtain user's location with BLE scanning (BLUETOOTH_SCAN is not using neverForLocation attribute in your App)