I'm just trying to create a dummy app for speech recognition on clicking a button (with no pop-ups or anything).
My Android manifest file:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="billobob.org.speechtest">
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
And the fragment housing what's actually going on:
package myandroid.org.speechtest;
import android.content.Intent;
import android.os.Bundle;
import android.speech.RecognitionListener;
import android.speech.RecognizerIntent;
import android.speech.SpeechRecognizer;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import java.util.ArrayList;
/**
* Simple app for recognizing speech
*/
public class MainActivityFragment extends Fragment {
protected static final int RESULT_SPEECH = 1234;
private TextView mSpeechTextView1;
private TextView mSpeechTextView2;
private Button mSpeechButton;
private String speechString;
private SpeechRecognizer mSpeechRecognizer;
private Intent mSpeechRecognizerIntent;
boolean mIsListening = false;
public MainActivityFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main, container, false);
mSpeechTextView1 = (TextView) view.findViewById(R.id.textView1);
mSpeechTextView2 = (TextView) view.findViewById(R.id.textView2);
mSpeechButton = (Button) view.findViewById(R.id.speechButton);
mSpeechRecognizer = SpeechRecognizer.createSpeechRecognizer(this.getContext());
mSpeechRecognizerIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
mSpeechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
mSpeechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, this.getActivity().getPackageName());
SpeechRecognitionListener listener = new SpeechRecognitionListener();
mSpeechRecognizer.setRecognitionListener(listener);
mSpeechButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!mIsListening)
{
Log.d("UUXX", "clicked");
mIsListening = true;
mSpeechRecognizer.startListening(mSpeechRecognizerIntent);
}
}
});
return view;
}
#Override
public void onDestroyView() {
if (mSpeechRecognizer != null)
{
mSpeechRecognizer.stopListening();
mSpeechRecognizer.cancel();
mSpeechRecognizer.destroy();
}
super.onDestroyView();
}
protected class SpeechRecognitionListener implements RecognitionListener {
#Override
public void onReadyForSpeech(Bundle params) {
Log.d("UUSP", "in read");
}
#Override
public void onBeginningOfSpeech() {
Log.d("UUSP", "begin!");
}
#Override
public void onRmsChanged(float rmsdB) {
}
#Override
public void onBufferReceived(byte[] buffer) {
}
#Override
public void onEndOfSpeech() {
Log.d("UUSP", "end");
}
#Override
public void onError(int error) {
}
#Override
public void onResults(Bundle results) {
ArrayList<String> matches = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
Log.d("UUSP", matches != null ? matches.get(0) : null);
mIsListening = false;
mSpeechTextView1.setText(matches.get(0));
}
#Override
public void onPartialResults(Bundle partialResults) {
Log.d("UUSP", "partial...");
}
#Override
public void onEvent(int eventType, Bundle params) {
Log.d("UUSP", "event?");
}
}
}
The button registers the click, but nothing else happens. I noticed in the non-application log that the error:
05-20 20:56:32.022 18200-19108/? E/RecognitionService: call for recognition service without RECORD_AUDIO permissions
Always occurs, despite the fact that I ostensibly have permissions set in the manifest. I'm testing it on a 6P with Android Studio 2.1. Any help would be much appreciated!
For API 23+ (Android 6.0) it is not enough to just add permissions to the manifest. You need to request permissions at run time.
See the developer documents for more information:
https://developer.android.com/guide/topics/security/permissions.html#normal-dangerous
https://developer.android.com/training/permissions/requesting.html
You can verify this is the issue by changing your gradle targetSdkVersion back to 21. It will then use the old permission model on devices running API 23+
Add this code snippet at the instant where you want to access the audio recording feature.
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, 1);
This is asking for a run time permission to access the feature of recording audio. You can add any number of permissions in that array.
Add this in you manifest file:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
Related
I have an app made with android studio that connects to my propitiatory wind gauge that I developed. everything was working perfectly until I submitted it to google. They rejected it saying i need targetSdkVersion 29. when I build it with targetSdkVersion 29 the app no longer scans. But it works when I build it with targetSdkVersion 26
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.windgauge"
android:versionCode="1"
android:versionName="1.0" >
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-feature
android:name="android.hardware.bluetooth_le"
android:required="true" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.windgauge.ScanActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.windgauge.DeviceActivity" android:label="#string/app_name" />
</application>
</manifest>
ScanActivity.java
package com.windgauge;
import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.windgauge.util.BleUtil;
import com.windgauge.util.ScannedDevice;
import java.util.ArrayList;
import permissions.dispatcher.NeedsPermission;
import permissions.dispatcher.RuntimePermissions;
#RuntimePermissions
public class ScanActivity extends AppCompatActivity implements BluetoothAdapter.LeScanCallback {
private BluetoothAdapter mBTAdapter;
private DeviceAdapter mDeviceAdapter;
private boolean mIsScanning;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.activity_scan);
Button scan = findViewById(R.id.scan);
scan.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
ScanActivityPermissionsDispatcher.startScanWithPermissionCheck(ScanActivity.this);
}
});
init();
}
#Override
protected void onDestroy() {
super.onDestroy();
stopScan();
}
#Override
public void onLeScan(final BluetoothDevice newDeivce, final int newRssi,
final byte[] newScanRecord) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mDeviceAdapter.update(newDeivce, newRssi, newScanRecord);
}
});
}
private void init() {
// BLE check
if (!BleUtil.isBLESupported(this)) {
Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
finish();
return;
}
// BT check
BluetoothManager manager = BleUtil.getManager(this);
if (manager != null) {
mBTAdapter = manager.getAdapter();
}
if (mBTAdapter == null) {
Toast.makeText(this, R.string.bt_unavailable, Toast.LENGTH_SHORT).show();
finish();
return;
}
if (!mBTAdapter.isEnabled()) {
Toast.makeText(this, R.string.bt_disabled, Toast.LENGTH_SHORT).show();
finish();
return;
}
// init listview
ListView deviceListView = (ListView) findViewById(R.id.list);
mDeviceAdapter = new DeviceAdapter(this, R.layout.listitem_device,
new ArrayList<ScannedDevice>());
deviceListView.setAdapter(mDeviceAdapter);
deviceListView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterview, View view, int position, long id) {
ScannedDevice item = mDeviceAdapter.getItem(position);
if (item != null) {
Intent intent = new Intent(view.getContext(), DeviceActivity.class);
BluetoothDevice selectedDevice = item.getDevice();
intent.putExtra(DeviceActivity.EXTRA_BLUETOOTH_DEVICE, selectedDevice);
startActivity(intent);
// stop before change Activity
stopScan();
}
}
});
stopScan();
}
#NeedsPermission(Manifest.permission.ACCESS_COARSE_LOCATION)
void startScan() {
if ((mBTAdapter != null) && (!mIsScanning)) {
mBTAdapter.startLeScan(this);
mIsScanning = true;
setProgressBarIndeterminateVisibility(true);
invalidateOptionsMenu();
}
}
private void stopScan() {
if (mBTAdapter != null) {
mBTAdapter.stopLeScan(this);
}
mIsScanning = false;
setProgressBarIndeterminateVisibility(false);
invalidateOptionsMenu();
}
}
I am trying to get phone state using TelephoneManager class and using a job scheduler i have assigned a listener for onCallStateChangeListener() ... but still android 9 "Pie" kills every background task like my listener and jobScheduler ! so how can i solve this problem and get phone state while my app is in totally closed !
Note : I tried an app like Truecaller and it works just fine after closing the app! how can i get similar behavior on my app ?
MainActivity.java
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.content.ComponentName;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private static final int JOB_ID = 123;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
scheduleJob();
}
public void scheduleJob() {
ComponentName componentName = new ComponentName(this, ExampleJobService.class);
JobInfo info = new JobInfo.Builder(JOB_ID , componentName)
.setPersisted(true)
.setPeriodic(15 * 60 * 1000)
.build();
JobScheduler scheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);
int resultCode = scheduler.schedule(info);
if (resultCode == JobScheduler.RESULT_SUCCESS) {
Log.d(TAG, "Job scheduled");
} else {
Log.d(TAG, "Job scheduling failed");
}
}
public void cancelJob() {
JobScheduler scheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);
scheduler.cancel(123);
Log.d(TAG, "Job cancelled");
}
}
JobScheduler.java
import android.app.job.JobParameters;
import android.app.job.JobService;
import android.content.Context;
import android.os.Looper;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.widget.Toast;
public class ExampleJobService extends JobService {
private static final String TAG = "ExampleJobService";
boolean quitLooper;
TelephonyManager telephonyManager;
public void checkForIncomingCalls() {
telephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
new Thread(new Runnable() {
#Override
public void run() {
quitLooper = false;
Looper.prepare();
PhoneStateListener callStateListener = new PhoneStateListener() {
#Override
public void onCallStateChanged(int state, String phoneNumber) {
if(state==TelephonyManager.CALL_STATE_RINGING){
Toast.makeText(getApplicationContext(),"Phone Is Riging",
Toast.LENGTH_LONG).show();
}
if(state==TelephonyManager.CALL_STATE_OFFHOOK){
Toast.makeText(getApplicationContext(),"Phone is Currently in A call",
Toast.LENGTH_LONG).show();
}
if(state==TelephonyManager.CALL_STATE_IDLE){
Toast.makeText(getApplicationContext(),"phone is neither ringing nor in a call",
Toast.LENGTH_LONG).show();
}
}
};
telephonyManager.listen(callStateListener , PhoneStateListener.LISTEN_CALL_STATE);
Looper.loop();
}
}).start();
}
#Override
public boolean onStartJob(JobParameters params) {
Log.d(TAG, "Job started");
doBackgroundWork(params);
return true;
}
private void doBackgroundWork(final JobParameters params) {
new Thread(new Runnable() {
#Override
public void run() {
checkForIncomingCalls();
Log.d(TAG, "Job finished");
jobFinished(params, false);
}
}).start();
}
#Override
public boolean onStopJob(JobParameters params) {
Log.d(TAG, "Job cancelled before completion");
return true;
}
}
Manifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.devteam.test231">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".ExampleJobService"
android:permission="android.permission.BIND_JOB_SERVICE"/>
</application>
</manifest>
Thanks!
I'm attempting to send a string from wearable to mobile device using code below.
This implementation is based on https://github.com/twotoasters/Wear-MessageApiDemo/
Case there is an issue with the time delay in connecting to the device I've increased
CONNECTION_TIME_OUT_MS from 100 to 2000 (milliseconds).
To the mobile manifest I add :
<service
android:name=".ListenerService" >
<intent-filter>
<action android:name="com.google.android.gms.wearable.MESSAGE_RECEIVED" />
</intent-filter>
</service>
instead of
<service
android:name=".ListenerService" >
<intent-filter>
<action android:name="com.google.android.gms.wearable.BIND_LISTENER" />
</intent-filter>
</service>
as com.google.android.gms.wearable.BIND_LISTENER is deprecated
The code compiles but the message is not received by phone.
The method
private void showToast(String message) {
Log.d(TAG, "received message : " + message);
}
Should fire within the listenerService when a message is received.
The issue is a message is never received. Have I implemented the message api correctly ?
API version : 23
Source :
Mobile component
Kick off listenerService :
----------------------------------- MainActivity.onCreate ---------------
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new ListenerService();
}
Define the Listener service to listen for messages
----------------------------------- ListenerService ------------------
import android.util.Log;
import android.widget.TextView;
import com.google.android.gms.wearable.MessageEvent;
import com.google.android.gms.wearable.WearableListenerService;
public class ListenerService extends WearableListenerService {
private static final String TAG = "ListenerService";
TextView mTextView;
#Override
public void onMessageReceived(MessageEvent messageEvent) {
MainActivity.mTextView.setText("got message");
showToast(messageEvent.getPath());
}
private void showToast(String message) {
Log.d(TAG, "received message : " + message);
}
}
Define the service in the manifest
----------------------------------- AndroidManifest.xml ----------------
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.runner">
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.BODY_SENSORS"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.GPS_PROVIDER" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".ListenerService" >
<intent-filter>
<action android:name="com.google.android.gms.wearable.MESSAGE_RECEIVED" />
</intent-filter>
</service>
</application>
</manifest>
Wear component
MainActivity :
package common;
import android.content.Context;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.support.wearable.activity.WearableActivity;
import android.support.wearable.view.BoxInsetLayout;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.wearable.Node;
import com.google.android.gms.wearable.NodeApi;
import com.google.android.gms.wearable.Wearable;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
public class MainActivity extends WearableActivity {
private static final long CONNECTION_TIME_OUT_MS = 2000;
private static final String MESSAGE = "Hello Wear!";
private GoogleApiClient client;
private String nodeId;
private static final String TAG = "MainActivity";
private BoxInsetLayout mContainerView;
/**
* Initializes the GoogleApiClient and gets the Node ID of the connected device.
*/
private void initApi() {
client = getGoogleApiClient(this);
retrieveDeviceNode();
}
/**
* Returns a GoogleApiClient that can access the Wear API.
* #param context
* #return A GoogleApiClient that can make calls to the Wear API
*/
private GoogleApiClient getGoogleApiClient(Context context) {
return new GoogleApiClient.Builder(context)
.addApi(Wearable.API)
.build();
}
/**
* Connects to the GoogleApiClient and retrieves the connected device's Node ID. If there are
* multiple connected devices, the first Node ID is returned.
*/
private void retrieveDeviceNode() {
new Thread(new Runnable() {
#Override
public void run() {
client.blockingConnect(CONNECTION_TIME_OUT_MS, TimeUnit.MILLISECONDS);
NodeApi.GetConnectedNodesResult result =
Wearable.NodeApi.getConnectedNodes(client).await();
List<Node> nodes = result.getNodes();
if (nodes.size() > 0) {
Log.d(TAG, "nodeId "+nodeId);
nodeId = nodes.get(0).getId();
}
client.disconnect();
}
}).start();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initApi();
sendToast();
}
/**
* Sends a message to the connected mobile device, telling it to show a Toast.
*/
private void sendToast() {
if (nodeId != null) {
new Thread(new Runnable() {
#Override
public void run() {
client.blockingConnect(CONNECTION_TIME_OUT_MS, TimeUnit.MILLISECONDS);
Wearable.MessageApi.sendMessage(client, nodeId, MESSAGE, null);
client.disconnect();
}
}).start();
}
}
}
Update :
Here is the class added to mobile module to listen for received messages :
package com.receivers;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class MessageListener extends BroadcastReceiver {
private static final String TAG = "MessageListener";
#Override
public void onReceive(Context context, Intent intent) {
String str = intent.getAction();
Log.i(TAG, "onReceive triggered : "+str);
}
}
Config of MessageListener in AndroidManifest.xml :
<receiver android:name="com.receivers.MessageListener">
<intent-filter>
<action android:name="com.google.android.gms.wearable.MESSAGE_RECEIVED" />
</intent-filter>
</receiver>
I've tried setting a breakpoint at line String str = intent.getAction(); but onReceive method does not appear to be invoked.
Within the wear module the method onNodeFound() does appear to send the message correctly as this line Wearable.MessageApi.sendMessage(googleApiClient, nodeId, MESSAGE_PATH, "Hello Wear!".getBytes(Charset.forName("UTF-8"))); is being invoked. Have i setup the MessageListener correctly ?
Update 2 :
ReceiverActivity :
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
public class ReceiverActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter("custom-event-name"));
}
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Get extra data included in the Intent
String message = intent.getStringExtra("EXTRA_MESSAGE");
Log.d("receiver", "Got message: " + message);
}
};
#Override
protected void onDestroy() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
super.onDestroy();
}
}
Within the ListenerService , method onMessageReceived is being fired and here trying to broadcast the message :
#Override
public void onMessageReceived(MessageEvent messageEvent) {
super.onMessageReceived(messageEvent);
Log.d("tester", "received a message from wear: " + new String(messageEvent.getData()));
final String message = new String(messageEvent.getData());
final Intent messageIntent = new Intent();
messageIntent.putExtra("EXTRA_MESSAGE", message); // define your extra
LocalBroadcastManager.getInstance(this).sendBroadcast(messageIntent);
}
Starting the activity in AndroidManifest.xml :
<activity android:name=".ReceiverActivity">
</activity>
But ReceiverActivity does not appear to receive message, is ReceiverActivity setup correctly ?
Update 3 :
As per comment to start the activity I add :
Intent intent = new Intent(this, ReceiverActivity.class);
startActivity(intent);
to MainActivity.onCreate :
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = new Intent(this, ReceiverActivity.class);
startActivity(intent);
......
new ListenerService();
This is not how you start any Service. This just creates a Servie instance that will do nothing and will be collected after onCreate() exits.
This Service will be started by the system when you'll receive a message. You only need to define it in the manifest. Also, you might need to define a path for messages you receive, like
<service android:name=".ListenerService" >
<intent-filter>
<action android:name="com.google.android.gms.wearable.MESSAGE_RECEIVED" />
<data android:scheme="wear" android:host="*" android:pathPrefix="/message"/>
</intent-filter>
</service>
That's all you need for your Service to be set up. Also, keep in mind that in order to receive messages your Wear app and Handheld app should have the same package name (applicationId). Double check you don't have mismatching applicationId for flavors or buildTypes. So if you have applicationId in build.gradle, make sure they match for both wear and handhelp app projects
defaultConfig {
applicationId "com.runner"
About updating UI:
#Override
public void onMessageReceived(MessageEvent messageEvent) {
MainActivity.mTextView.setText("got message");
}
This is not a way to interact a Service with Activity.
Activity might or might not be running when Service runs. Only update Activtity UI from Activity. If you need to show user a message, use a BroadcastReceiver or an Observer.
Note that onMessageReceived() will not be ran on Main UI thread, so use a Handler before showing a Toast there.
So if you want to pass the Message from this Service to Activity, one of the ways is like
#Override
public void onMessageReceived(MessageEvent messageEvent) {
final byte[] data = messsageEvent.getData();
if (data != null) {
final String message = new String(data, Charset.forName("UTF-8"));
final Intent messageIntent = new Intent("custom-event-name");
intent.putExtra(EXTRA_MESSAGE, message); // define your extra
LocalBroadcastManager.getInstance(this).sendBroadcast(messageIntent);
// Register BroadcastReiver from LocalBroadcastManager in your Activity to receive this broadcast
}
}
Or if you want to start Activity if it's not running, you need a different approach:
<activity
android:name=".ReceiverActivity"
android:launchMode="singleTop"/>
Service:
#Override
public void onMessageReceived(MessageEvent messageEvent) {
final byte[] data = messsageEvent.getData();
if (data != null) {
final String message = new String(data, Charset.forName("UTF-8"));
final Intent activityIntent = new Intent(this, ReceiverActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("EXTRA_MESSAGE", message);
startActivity(intent);
}
}
// In this case, in Activity, if it's explicitly started, you don't need a BroadcastReceiver
// Instead, you can get the extra from Activity Intent
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
handleIntent(getIntent());
}
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
handleIntent(intent);
}
private void handleIntent(Intent intent) {
String message = intent.getStringExtra("EXTRA_MESSAGE");
}
In Wear component
initApi();
sendToast();
you use different threads that may run simultaneously so when sendToast() runs you may actually have nodeId not resolved yet.
What I suggest doing is connecting GoogleApiClient in onCreate() with a Listener. Once the client connects, start getting the node. You don't need to spawn your own threads, the API is asynchronous if you use setResultCallback() instead of await()
Edit 14/02/2018: as Rajesh mentioned in the comments, Wearable.API is deprecated. The answer below refers to old API, which were new on the time of writing. I am leaving the old answer as is, but I don't have time to investigate how to do this with new APIs.
private static final String MESSAGE_PATH = "/message";
private GoogleApiClient googleApiClient;
#Override
protected void onCerate(Bundle state) {
super.onCreate(state);
googleApiClient = getGoogleApiClient(this);
googleApiClient.connect();
}
#Override
protected void onDestroy() {
super.onDestroy();
googleApiClient.disconnect();
}
private GoogleApiClient getGoogleApiClient(Context context) {
return new GoogleApiClient.Builder(context)
.addApi(Wearable.API)
.addConnectionCallbacks(mConnectionCallbacks)
.build();
}
private void findNodes() {
Wearable.NodeApi.getConnectedNodes(googleApiClient).setResultCallback(
new ResultCallback<NodeApi.GetConnectedNodesResult>() {
#Override
public void onResult(
#NonNull final NodeApi.GetConnectedNodesResult getConnectedNodesResult) {
List<Node> nodes = result.getNodes();
if (nodes != null && !nodes.isEmpty()) {
nodeId = nodes.get(0).getId();
Log.d(TAG, "nodeId "+ nodeId);
onNodeFound();
}
}
});
}
private void onNodeFound() {
if (nodeId != null) {
// Now you have your node, send a message, make sure the path starts like the path in manifest
// What you thought is a message is actually a path, and the actual message is the byte array.
// You may concat your message in path though, but keep in mind you will have to parse the string then
Wearable.MessageApi.sendMessage(client, nodeId, MESSAGE_PATH, "Hello Wear!".getBytes(Charset.forName("UTF-8")));
}
}
private final GoogleApiClient.ConnectionCallbacks mConnectionCallbacks
= new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(#Nullable final Bundle bundle) {
findNodes();
}
#Override
public void onConnectionSuspended(final int i) {
}
};
Ok, so I'm trying to implement Google Play Games Services into my libGDX game. I followed the tutorial here: http://helios.hud.ac.uk/u1070589/blog/?p=202
When i run my game on my nexus, it force closes and logcat gives this Fatal Exception:
java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.ggtized.bb/com.ggtized.bb.MainActivity}: java.lang.ClassNotFoundException: Didn't find class "com.ggtized.bb.MainActivity" on path: DexPathList...
Without the implementation, my game works fine. But the tutorial seems to have been a success for many and i want GPGS too..
What is causing this error. I have no idea.. Can someone help and might tell me whats the problem? Thank you for your replies!!
Here's my androidmanifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ggtized.bb"
android:versionCode="0"
android:versionName="1">
<uses-sdk
android:minSdkVersion="9"
android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
<meta-data
android:name="com.google.android.gms.games.APP_ID"
android:value="#string/app_id" />
<activity
android:name="com.ggtized.bb.MainActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:label="#string/app_name"
android:screenOrientation="portrait" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.google.android.gms.ads.AdActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize" />
</application>
</manifest>
Here's my main Android activity:
package com.ggtized.bb;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.RelativeLayout;
import com.badlogic.gdx.backends.android.AndroidApplication;
import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration;
//import com.google.android.gms.ads.AdListener;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.AdSize;
import com.google.android.gms.ads.AdView;
import com.google.android.gms.games.leaderboard.Leaderboard;
import com.google.android.gms.games.leaderboard.LeaderboardScoreBuffer;
import com.google.android.gms.games.leaderboard.OnLeaderboardScoresLoadedListener;
import com.google.example.games.basegameutils.GameHelper;
import com.google.example.games.basegameutils.GameHelper.GameHelperListener;
import com.ggtized.bb.GoogleInterface;
import com.ggtized.bb.BGame;
public class MainActivity extends AndroidApplication implements
GameHelperListener, GoogleInterface {
// ****AdMob
private AdView adView; // small ad
// First Ad Code
private static final String ADCODE = "ca-app-pub-6026787001894298/9413212162";
// First time an Ad is loaded
boolean firstTime = true;
// *************GPGS
private GameHelper aHelper;
private OnLeaderboardScoresLoadedListener theLeaderboardListener;
public MainActivity() {
aHelper = new GameHelper(this);
aHelper.enableDebugLog(true, "MYTAG");
// create a listener for getting raw data back from leaderboard
theLeaderboardListener = new OnLeaderboardScoresLoadedListener() {
public void onLeaderboardScoresLoaded(int arg0, Leaderboard arg1,
LeaderboardScoreBuffer arg2) {
System.out.println("In call back");
for (int i = 0; i < arg2.getCount(); i++) {
System.out.println(arg2.get(i).getScoreHolderDisplayName()
+ " : " + arg2.get(i).getDisplayScore());
}
}
};
}
// *************GPGS end
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ****AdMob
AndroidApplicationConfiguration cfg = new AndroidApplicationConfiguration();
cfg.useGL20 = false;
// *************GPGS
aHelper.setup(this);
// *************GPGS end
// initialize(new Game(), cfg);
this.getWindow().addFlags(
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
final RelativeLayout layout = new RelativeLayout(this);
requestWindowFeature(Window.FEATURE_NO_TITLE); // no title is needed
// Do the stuff that initialize() would do for you
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().clearFlags(
WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
// here we need to create the proper AdViews: one for the banner, and
// one for the full screen one
adView = new AdView(this);
adView.setAdSize(AdSize.SMART_BANNER);
adView.setAdUnitId(ADCODE); // Put in your secret key here
// Here we create the instance of the MyApp and we pass it the
// RequestHandler which implements the IReqHandler interface
View gameView = initializeForView(new BGame(null, this), cfg);
// Optionally populate the ad request builder.
AdRequest adRequest = new AdRequest.Builder()
.addTestDevice(AdRequest.DEVICE_ID_EMULATOR) // Emulator
.addTestDevice("775A90563E174E374BC2617A3FD652B1") // testdevice
.build();
adView.loadAd(adRequest);
// Add the libgdx view
layout.addView(gameView);
// Add the AdMob view
final RelativeLayout.LayoutParams adParams = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
adParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
adParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
/*
* // Setting the ad listener to check if the ad is loaded before adding
* // view, solves the problem of skipping the first draw
* adView.setAdListener(new AdListener() {
*
* #Override public void onAdLoaded() {
*
* if (firstTime) { firstTime = false; layout.addView(adView, adParams);
* } } });
*/
layout.addView(adView, adParams);
// Setting the background adview to transparant also solves the problem
// of skipping the ad draw
adView.setBackgroundColor(Color.TRANSPARENT);
// Hook it all up
setContentView(layout);
// **************AdMob end
}
#Override
public void onResume() {
super.onResume();
if (adView != null) {
adView.resume();
}
}
#Override
public void onPause() {
// Pause the AdView.
if (adView != null) {
adView.pause();
}
super.onPause();
}
/** Called before the activity is destroyed. */
#Override
public void onDestroy() {
// Destroy the AdView.
if (adView != null) {
adView.destroy();
}
super.onDestroy();
}
// ****************GPGS
#Override
public void onStart(){
super.onStart();
aHelper.onStart(this);
}
#Override
public void onStop(){
super.onStop();
aHelper.onStop();
}
#Override
public void onActivityResult(int request, int response, Intent data) {
super.onActivityResult(request, response, data);
aHelper.onActivityResult(request, response, data);
}
public void onSignInFailed() {
System.out.println("sign in failed");
}
public void onSignInSucceeded() {
System.out.println("sign in succeeded");
}
public void Login() {
try {
runOnUiThread(new Runnable(){
//#Override
public void run(){
aHelper.beginUserInitiatedSignIn();
}
});
}catch (final Exception ex){
}
}
public void LogOut() {
try {
runOnUiThread(new Runnable(){
//#Override
public void run(){
aHelper.signOut();
}
});
}catch (final Exception ex){
}
}
public boolean getSignedIn() {
return aHelper.isSignedIn();
}
public void submitScore(int _score) {
System.out.println("in submit score");
aHelper.getGamesClient().submitScore(getString(R.string.leaderBoardID), _score);
}
public void getScores() {
startActivityForResult(aHelper.getGamesClient().getLeaderboardIntent(getString(R.string.leaderBoardID)), 105);
}
public void getScoresData() {
aHelper.getGamesClient().loadPlayerCenteredScores(theLeaderboardListener,
getString(R.string.leaderBoardID),
1,
1,
25) ;
}
// *************GPGS end
}
And here's my Main Game Class
package com.ggtized.bb;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Game;
import com.ggtized.Screens.SplashScreen;
import com.ggtized.BHelpers.AssetLoader;
import com.ggtized.BHelpers.IReqHandler;
public class BGame extends Game implements ApplicationListener {
// Code for Ads
public static IReqHandler ExternalHandler;
// *****GPGS
private GoogleInterface platformInterface;
public BGame(IReqHandler irh, GoogleInterface aInterface) {
BGame.ExternalHandler = irh;
platformInterface = aInterface;
platformInterface.Login();
}
#Override
public void create() {
AssetLoader.load();
setScreen(new SplashScreen(this));
}
#Override
public void dispose() {
super.dispose();
AssetLoader.dispose();
}
}
I finally managed to find a way to solve the issue. In your BaseGameUtils Build Path--->Librairies, you normally have a android-support-v4.jar (or a similar .jar). Delete it from the Build Path (you already have it in the Build Path of your main app, seems to be conflicting in this case).
I've set up the http://bingmapsandroidsdk.codeplex.com/ to try bing maps instead of google maps on Android. Because I was unable to set that up.
I'm able to run Bing maps on my emulator but I'm unable to run it on my device(Galaxy S2).
I have a wifi connection on my phone but I'm still unable to get past the load screen.
I also checked this question but it doesn't solve the problem Working on Emulator but not on the real Android device
So my code:
Manifest
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name="android.permission.ACCESS_GPS"></uses-permission>
<uses-sdk android:minSdkVersion="5" android:targetSdkVersion="15"/>
<application android:icon="#drawable/bingmaps_icon" android:label="#string/app_name" android:allowBackup="false">
<activity android:name=".MainActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="SplashActivity"></activity>
</application>
Starting Activity copied from the Bing-sdk
package org.bingmaps.app;
import java.util.HashMap;
import org.bingmaps.app.R;
import org.bingmaps.sdk.BingMapsView;
import org.bingmaps.sdk.Coordinate;
import org.bingmaps.sdk.EntityClickedListener;
import org.bingmaps.sdk.EntityLayer;
import org.bingmaps.sdk.MapLoadedListener;
import org.bingmaps.sdk.MapMovedListener;
import org.bingmaps.sdk.MapStyles;
import org.bingmaps.sdk.Pushpin;
import org.bingmaps.sdk.PushpinOptions;
import android.app.Activity;
import android.app.ProgressDialog;
import android.location.Location;
import android.location.LocationListener;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.ViewFlipper;
import android.widget.ZoomButton;
public class MainActivity extends Activity {
private BingMapsView bingMapsView;
private GPSManager _GPSManager;
private EntityLayer _gpsLayer;
private ProgressDialog _loadingScreen;
private Activity _baseActivity;
CharSequence[] _dataLayers;
boolean[] _dataLayerSelections;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
//OPTION Lock map orientation
setRequestedOrientation(1);
setContentView(R.layout.main);
Initialize();
}
private void Initialize()
{
_baseActivity = this;
_GPSManager = new GPSManager((Activity)this, new GPSLocationListener());
//Add more data layers here
_dataLayers = new String[] { getString(R.string.traffic)};
_dataLayerSelections = new boolean[ _dataLayers.length ];
_loadingScreen = new ProgressDialog(this);
_loadingScreen.setCancelable(false);
_loadingScreen.setMessage(this.getString(R.string.loading) + "...");
bingMapsView = (BingMapsView) findViewById(R.id.mapView);
//Create handler to switch out of Splash screen mode
final Handler viewHandler = new Handler() {
public void handleMessage(Message msg) {
((ViewFlipper) findViewById(R.id.flipper)).setDisplayedChild(1);
}
};
//Add a map loaded event handler
bingMapsView.setMapLoadedListener(new MapLoadedListener() {
public void onAvailableChecked() {
// hide splash screen and go to map
viewHandler.sendEmptyMessage(0);
//Add GPS layer
_gpsLayer = new EntityLayer(Constants.DataLayers.GPS);
bingMapsView.getLayerManager().addLayer(_gpsLayer);
UpdateGPSPin();
}
});
//Add a entity clicked event handler
bingMapsView.setEntityClickedListener(new EntityClickedListener() {
public void onAvailableChecked(String layerName, int entityId) {
HashMap<String, Object> metadata = bingMapsView.getLayerManager().GetMetadataByID(layerName, entityId);
DialogLauncher.LaunchEntityDetailsDialog(_baseActivity, metadata);
}
});
//Load the map
bingMapsView.loadMap(Constants.BingMapsKey, _GPSManager.GetCoordinate(), Constants.DefaultGPSZoomLevel, this.getString(R.string.mapCulture));
// Create zoom out button functionality
final ZoomButton zoomOutBtn = (ZoomButton) findViewById(R.id.zoomOutBtn);
zoomOutBtn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
bingMapsView.zoomOut();
}
});
// Create zoom button in functionality
final ZoomButton zoomInBtn = (ZoomButton) findViewById(R.id.zoomInBtn);
zoomInBtn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
bingMapsView.zoomIn();
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.layout.menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
//Map Mode menu items
case R.id.autoBtn:
bingMapsView.setMapStyle(MapStyles.Auto);
item.setChecked(!item.isChecked());
return true;
case R.id.roadBtn:
bingMapsView.setMapStyle(MapStyles.Road);
item.setChecked(!item.isChecked());
return true;
case R.id.aerialBtn:
bingMapsView.setMapStyle(MapStyles.Aerial);
item.setChecked(!item.isChecked());
return true;
case R.id.birdseyeBtn:
bingMapsView.setMapStyle(MapStyles.Birdseye);
item.setChecked(!item.isChecked());
return true;
//More option items
case R.id.aboutMenuBtn:
DialogLauncher.LaunchAboutDialog(this);
return true;
case R.id.layersMenuBtn:
DialogLauncher.LaunchLayersDialog(this, bingMapsView, _dataLayers, _dataLayerSelections);
return true;
case R.id.clearMapMenuBtn:
bingMapsView.getLayerManager().clearLayer(null);
//unselect all layers
for(int i=0;i<_dataLayerSelections.length;i++){
_dataLayerSelections[i] = false;
}
//re-add GPS layer
bingMapsView.getLayerManager().clearLayer(Constants.DataLayers.GPS);
UpdateGPSPin();
return true;
//GPS Menu Item
case R.id.gpsMenuBtn:
Coordinate coord = _GPSManager.GetCoordinate();
if(coord != null){
//Center on users GPS location
bingMapsView.setCenterAndZoom(coord, Constants.DefaultGPSZoomLevel);
}
return true;
//Search Menu Item
case R.id.searchMenuBtn:
DialogLauncher.LaunchSearchDialog(this, bingMapsView, loadingScreenHandler);
return true;
//Directions Menu Item
case R.id.directionsMenuBtn:
DialogLauncher.LaunchDirectionsDialog(this, bingMapsView, loadingScreenHandler);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void UpdateGPSPin(){
PushpinOptions opt = new PushpinOptions();
opt.Icon = Constants.PushpinIcons.GPS;
Pushpin p = new Pushpin(_GPSManager.GetCoordinate(), opt);
if (p.Location != null) {
_gpsLayer.clear();
_gpsLayer.add(p);
_gpsLayer.updateLayer();
}
}
#SuppressWarnings("unused")
private final MapMovedListener mapMovedListener = new MapMovedListener() {
public void onAvailableChecked() {
//OPTION Add logic to Update Layers here.
//This will update data layers when the map is moved.
}
};
/**
* Handler for loading Screen
*/
protected Handler loadingScreenHandler = new Handler() {
public void handleMessage(Message msg) {
if (msg.arg1 == 0) {
_loadingScreen.hide();
} else {
_loadingScreen.show();
}
}
};
public class GPSLocationListener implements LocationListener {
public void onLocationChanged(Location arg0) {
UpdateGPSPin();
}
public void onProviderDisabled(String arg0) {
}
public void onProviderEnabled(String arg0) {
}
public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
}
}
}
ERRORS from LOGCAT: non
bing maps for android does not work for android versions 3.0 and higher