I've seen some posts that seem similar, but they're all fairly old and slightly different. I have an app whose codebase I have not touched in a long time. It makes use of the android SpeechRecognizer Service, and has a toggle for the EXTRA_PREFER_OFFLINE intent param. Previously this was working with no issues, but since I've recently dusted it off I noticed that offline functionality immediately returns with error code 7 NO_MATCH.
I have confirmed that offline language packs are installed, and wrote some stand alone code to test SpeechRecognizer outside my larger code base.
I've not been able to find any documented solutions for the NO_MATCH error, but surely it must occur elsewhere.
For context: This was previously working last year/earlier this year (I've seen people claim this wasn't possible after 2015/17) and on Android 8
Sample code snippet:
speechRecognizer = SpeechRecognizer.createSpeechRecognizer(getContext());
final Intent speechRecognizerIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
speechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
speechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true);
speechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_PREFER_OFFLINE, true);
speechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, "en-US");
speechRecognizer.setRecognitionListener(new RecognitionListener() {
#Override
public void onReadyForSpeech(Bundle bundle) {
listening = true;
label.setText(R.string.listening_true);
}
#Override
public void onBeginningOfSpeech() {
}
#Override
public void onRmsChanged(float v) {
}
#Override
public void onBufferReceived(byte[] bytes) {
}
#Override
public void onEndOfSpeech() {
label.setText(R.string.listening_false);
listening = false;
}
#Override
public void onError(int i) {
Log.e(TAG, "Error code " + i);
label.setText(R.string.listening_false);
listening = false;
}
#Override
public void onResults(Bundle bundle) {
ArrayList<String> data = bundle.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
if (data != null && data.size() > 0) {
resultsTextView.setText(data.get(0));
resultsTextView.setTextColor(getResources().getColor(R.color.colorAccent));
listening = false;
}
}
#Override
public void onPartialResults(Bundle bundle) {
ArrayList<String> data = bundle.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
if (data != null && data.size() > 0) {
Log.i(TAG, "how many partial results? " + data.size());
resultsTextView.setText(data.get(0));
resultsTextView.setTextColor(getResources().getColor(R.color.design_default_color_primary));
Log.i(TAG, "Partial results: " + data);
}
}
#Override
public void onEvent(int i, Bundle bundle) {
}
});
view.findViewById(R.id.button_mic).setOnClickListener(view1 -> {
if (!listening) {
speechRecognizer.startListening(speechRecognizerIntent);
} else {
speechRecognizer.stopListening();
}
});
Google app's voice input could work offline previously, but unfortunately, this feature has been removed since version 11 (released in March 2020).
Thus, to use this feature, we have to keep the version of Google app on device at 10.99.8 or older.
However, on some new device released after March 2020, the pre-installed version of Google app is already 11 or 12, so it is not a simple task to downgrade it to an older version.
So we need to use adb command to downgrade it from PC. This command will try to force downgrade the app for the 'current user': adb install -r -d --user 0 google.apk
The answer is that this is no loner supported. If you need a short term fix then go to your "Google", not "Google Play Services", app and uninstall updates from the hamburger menu. This seems to downgrade a lot of libraries, including the voice recognition stuff.
A possibility might be to manually bring and load your own libraries, but I haven't tested this personally.
Related
So I have a billing client which I instantiate with
billingClient = BillingClient.newBuilder(this).setListener(this).build();
I then call
billingClient.startConnection(new BillingClientStateListener() {
#Override
public void onBillingSetupFinished(int responseCode) {
//TODO: use this for stuff
com.android.billingclient.api.Purchase.PurchasesResult result;
result = billingClient.queryPurchases(BillingClient.SkuType.SUBS);
Timber.d(result.toString());
}
#Override
public void onBillingServiceDisconnected() {
//TODO: use this for stuff
Timber.d("something went wrong ");
}
});
for whatever reason the breakpoint on the timber line always returns disconnected. can anyone provide insight or an example to how i would do this?
I came across this problem.
Be also sure to start the connection:
mBillingClient = BillingClient.newBuilder(mContext).setListener(purchasesUpdatedListener).build();
mBillingClient.startConnection(new BillingClientStateListener() {
#Override
public void onBillingSetupFinished(#BillingClient.BillingResponse int billingResponseCode) {
if (billingResponseCode == BillingClient.BillingResponse.OK) {
Log.d(TAG, "onBillingSetupFinished: BillingClient.BillingResponse.OK ");
}
}
#Override
public void onBillingServiceDisconnected() {
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
}
});
Turns out I was not using a version of my apk that was signed with the right version numbering and such. Once I fixed that I was able to connect to play services and figure out what i wanted.
I know it's too late to answer this, but i was missing this permission in manifest,
<uses-permission android:name="com.android.vending.BILLING" />
hope that helps someone
If you use custom rom or rooted device it probably won't work.
Run a system image on which the Google Play client application is preinstalled.
If Google Play is not preinstalled in the system image, your application won't be able to communicate with the Google Play licensing server.
https://developer.android.com/google/play/licensing/setting-up
I am using the Google Snapshot API in Android.
I use this code to get the user's activity and store it to Firebase.
//Get user's current activity
private void myCurrentActivity(final String timestamp) {
if (checkPermission()) {
Awareness.SnapshotApi.getDetectedActivity(mGoogleApiClient)
.setResultCallback(new ResultCallback<DetectedActivityResult>() {
#Override
public void onResult(#NonNull DetectedActivityResult detectedActivityResult) {
if (detectedActivityResult.getStatus().isSuccess()) {
Log.d(TAG, "myCurrentActivity - SUCCESS");
ActivityRecognitionResult activityRecognitionResult = detectedActivityResult.getActivityRecognitionResult();
databaseReference.child(getUID(getApplicationContext(), "myCurrentActivity")).child(timestamp).child("activity").setValue(getActivityString(activityRecognitionResult.getMostProbableActivity().getType()));
Log.d(TAG, "Most Propable Activity : " + getActivityString(activityRecognitionResult.getMostProbableActivity().getType()));
} else {
Log.d(TAG, "myCurrentActivity - FAILURE");
databaseReference.child(getUID(getApplicationContext(), "myCurrentActivity")).child(timestamp).child("activity").setValue("null");
}
}
});
}
}
The problem is that the onResult function is never executed when i run it.
Do you have any ideas what may cause this ?
Thank you.
EDIT: I just ran it in the emulator and it's working without problems. Is it possible that this has something to do with my device ?
Wifi P2P service discovery is not behaving as expected. I am seeing intermittent issues where the DNSSD listeners are not called always and hence I have no clue of nearby devices running the same app. I am using the following two APIs - one to register a service to be discovered by other devices and the other to discover the nearby services running on other devices. Any idea if I am doing anything wrong here or is there some specific sequence of other android API calls that need to be made before I call these APIs to ensure that the listeners are always called whenever there is a new service registered or even if a service is registered before we call the API to discover the local services.
API to register a local service:
private void registerService() {
Map<String, String> values = new HashMap<String, String>();
values.put("name", "Steve");
values.put("port", "8080");
WifiP2pServiceInfo srvcInfo = WifiP2pDnsSdServiceInfo.newInstance(mMyDevice.deviceName, "_http._tcp", values);
manager.addLocalService(channel, srvcInfo, new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
Toast.makeText(WiFiDirectActivity.this, "Local service added successfully",
Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(int reasonCode) {
Toast.makeText(WiFiDirectActivity.this, "Local service addition failed : " + reasonCode,
Toast.LENGTH_SHORT).show();
}
});
}
API to discover local services:
public void discoverService() {
manager.clearServiceRequests(channel, null);
DnsSdTxtRecordListener txtListener = new DnsSdTxtRecordListener() {
#Override
/* Callback includes:
* fullDomain: full domain name: e.g "printer._ipp._tcp.local."
* record: TXT record data as a map of key/value pairs.
* device: The device running the advertised service.
*/
public void onDnsSdTxtRecordAvailable(String fullDomain, Map record, WifiP2pDevice device) {
Log.d(TAG, "DnsSdTxtRecord available -" + record.toString());
}
};
DnsSdServiceResponseListener servListener = new DnsSdServiceResponseListener() {
#Override
public void onDnsSdServiceAvailable(String instanceName, String registrationType, WifiP2pDevice resourceType) {
Log.d(TAG, "onBonjourServiceAvailable " + instanceName);
}
};
manager.setDnsSdResponseListeners(channel, servListener, txtListener);
WifiP2pDnsSdServiceRequest serviceRequest = WifiP2pDnsSdServiceRequest.newInstance();
manager.addServiceRequest(channel, serviceRequest, new ActionListener() {
#Override
public void onSuccess() {
// Success!
Log.d(TAG, "addServiceRequest success");
}
#Override
public void onFailure(int code) {
// Command failed. Check for P2P_UNSUPPORTED, ERROR, or BUSY
Log.d(TAG, "addServiceRequest failure with code " + code);
}
});
manager.discoverServices(channel, new ActionListener() {
#Override
public void onSuccess() {
// Success!
Log.d(TAG, "discoverServices success");
}
#Override
public void onFailure(int code) {
// Command failed. Check for P2P_UNSUPPORTED, ERROR, or BUSY
if (code == WifiP2pManager.P2P_UNSUPPORTED) {
Log.d(TAG, "P2P isn't supported on this device.");
} else {
Log.d(TAG, "discoverServices failure");
}
}
});
}
Note: manager & channel are initialized as
WifiP2pManager manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
Channel channel = manager.initialize(this, getMainLooper(), null);
WifiP2p (in general):
Some time ago I was developing an application with a pretty complex network connectivity system based on WifiP2p with Service Broadcasting/Discovery. And based on that experience I already wrote few posts here on SO about how difficult, wearing and problematic that is. Here are two of them (they are quite full of the inside knowledge I acquired about WifiP2p with Service Discovery, and WifiP2p itself):
Why is discovering peers for Android WifiDirect so unreliable
Wi-fi P2P. Inform all peers available of some event
I would advise you to read both of my answers (even though they are focused a bit more on the WifiP2p itself). They should give you some perspective on the things you should be looking for when working with the WifiP2p Service Discovery.
I can easily say that if you want to build an efficient, relatively reliable and robust WifiP2p connection system (especially with Service Discovery), you will have to work your ass off.
WifiP2p Service Discovery:
To better answer your exact question, I will tell you what I did (different from you) to make my Service Discovery work pretty reliably.
1. Broadcasting Service:
First of all: before registering your Service (with addLocalService method) you should use the WifiP2pManager's clearLocalServices method. And it is important, that you should only call addLocalService if the listener passed in the clearLocalServices returned with the onSuccess callback.
Although this sets up the broadcasting pretty nicely, I found that other nodes were not always able to detect the broadcasted service (especially when those nodes weren't already actively detecting services at the moment of registering your local Service - but they "joined" later). I couldn't find a way to fix this issue 100% reliably. And believe me I was trying probably everything WifiP2p-related. And no, the clearLocalServices-addLocalService sequence wasn't really giving satisfying results. Or more so: doing something different was working much better. What I decided to do, was after I successfully added local service (onSuccess callback from addLocalService), I started a Thread that would periodically call WifiP2pManager's method discoverPeers. That seemed to be forcing to rebroadcast all the service information.
So... basically the base of your broadcasting code should look more-less like this (bare in mind that every single piece of code I will post here is stripped-off of all "checks" if the network connectivity system is in the right state, you should design them yourself to fit your solution the best):
public void startBroadcastingService(){
mWifiP2pManager.clearLocalServices(mWifiP2pChannel, new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
mWifiP2pManager.addLocalService(mWifiP2pChannel, mWifiP2pServiceInfo,
new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
// service broadcasting started
mServiceBroadcastingHandler
.postDelayed(mServiceBroadcastingRunnable,
SERVICE_BROADCASTING_INTERVAL);
}
#Override
public void onFailure(int error) {
// react to failure of adding the local service
}
});
}
#Override
public void onFailure(int error) {
// react to failure of clearing the local services
}
});
}
where the mServiceBroadcastingRunnable should be:
private Runnable mServiceBroadcastingRunnable = new Runnable() {
#Override
public void run() {
mWifiP2pManager.discoverPeers(mWifiP2pChannel, new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
}
#Override
public void onFailure(int error) {
}
});
mServiceBroadcastingHandler
.postDelayed(mServiceBroadcastingRunnable, SERVICE_BROADCASTING_INTERVAL);
}
};
2. Discovering Service:
For the discovering of your service I used similar approach. Both with the setting up the discovering, and with trying to force "rediscovery" of services.
Setting up was performed with the sequence of the following three WifiP2pManager's methods:
removeServiceRequest, addServiceRequest, discoverServices
They were called in this exact order and a particular method (second or the third one to be exact) has been called only after the previous one had "returned" with the onSuccess callback.
The rediscovery of services was being performed with the intuitive method (just by repeating the mentioned sequence: removeServiceRequest -> addServiceRequest -> discoverServices).
The base of my code looked more-less like this (to start Service Discovery I would first call prepareServiceDiscovery() and then startServiceDiscovery()):
public void prepareServiceDiscovery() {
mWifiP2pManager.setDnsSdResponseListeners(mWifiP2pChannel,
new WifiP2pManager.DnsSdServiceResponseListener() {
#Override
public void onDnsSdServiceAvailable(String instanceName,
String registrationType, WifiP2pDevice srcDevice) {
// do all the things you need to do with detected service
}
}, new WifiP2pManager.DnsSdTxtRecordListener() {
#Override
public void onDnsSdTxtRecordAvailable(
String fullDomainName, Map<String, String> record,
WifiP2pDevice device) {
// do all the things you need to do with detailed information about detected service
}
});
mWifiP2pServiceRequest = WifiP2pDnsSdServiceRequest.newInstance();
}
private void startServiceDiscovery() {
mWifiP2pManager.removeServiceRequest(mWifiP2pChannel, mWifiP2pServiceRequest,
new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
mWifiP2pManager.addServiceRequest(mWifiP2pChannel, mWifiP2pServiceRequest,
new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
mWifiP2pManager.discoverServices(mWifiP2pChannel,
new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
//service discovery started
mServiceDiscoveringHandler.postDelayed(
mServiceDiscoveringRunnable,
SERVICE_DISCOVERING_INTERVAL);
}
#Override
public void onFailure(int error) {
// react to failure of starting service discovery
}
});
}
#Override
public void onFailure(int error) {
// react to failure of adding service request
}
});
}
#Override
public void onFailure(int reason) {
// react to failure of removing service request
}
});
}
the mServiceDiscoveringRunnable was just:
private Runnable mServiceDiscoveringRunnable = new Runnable() {
#Override
public void run() {
startServiceDiscovery();
}
};
All this made my system work quite well. It wasn't perfect yet, but with the lack of documentation on this subject I think I couldn't do much more to improve it.
If you test this approach, be sure to tell me how it works for you (or if it works for you ;) ).
if the problem is the detection of the service i believe that crearing group is the best way to make the device and service detectable but the if created group in the all devices then you cannot connect in direct.
but as wifi network.
i do it every day and it works.
I´m using the Android IBeacon Library for a Project. I need to create a Service that starts ranging for beacons in the background and notify the user when it finds one (the nearest one). I have searched a lot and coded based on many examples I have found, but still it doesn´t work. Using logs I found that the IBeaconManager doesn't bind, so onIBeaconServiceConnect never gets called. I have already tried some solutions I found here but none of them has been useful. I would really appreciate if someone could help me solving this problem. I post some of my code here
public class RangingService extends Service implements IBeaconConsumer
{
private IBeaconManager beaconManager;
#Override
public void onCreate()
{
super.onCreate();
beaconManager = IBeaconManager.getInstanceForApplication(this);
Log.d("RangingService","Created beaconManager instance");
beaconManager.setBackgroundBetweenScanPeriod(120000);
beaconManager.setBackgroundScanPeriod(30000);
beaconManager.bind(this);
if(beaconManager.isBound(this))
{
Log.d("RangingService","Beacon manager bound");
}
else
{
Log.d("RangingService","Beacon manager not bound");
}
//Show the service has started
notify("RangingService created", "RangingService has started");
}
#Override
public void onDestroy()
{
super.onDestroy();
beaconManager.unBind(this);
}
#Override
public void onIBeaconServiceConnect()
{
Log.d("RangingService", "Entering onIBeaconServiceConnect");
beaconManager.setRangeNotifier(new RangeNotifier() {
#Override
public void didRangeBeaconsInRegion(Collection<IBeacon> beacons, Region region)
{
if(beacons.size() > 0)
{
IBeacon nearestBeacon = beacons.iterator().next();
for(IBeacon b : beacons)
{
if(nearestBeacon.getProximity() == IBeacon.PROXIMITY_UNKNOWN)
{
nearestBeacon = b;
}
else
{
if(b.getProximity() != IBeacon.PROXIMITY_UNKNOWN)
{
if(b.getAccuracy() < nearestBeacon.getAccuracy())
{
nearestBeacon = b;
}
}
}
}
Log.d("RangingService","Nearest Beacon Found "+nearestBeacon.getMajor()+";"+nearestBeacon.getMinor());
notify("Beacon read","Major: "+nearestBeacon.getMajor()+"; Minor: "+nearestBeacon.getMinor());
}
else
{
Log.d("RangingService","No beacons");
}
}
});
try
{
Log.d("RangingService", "Entering startRangingBeacons");
beaconManager.startRangingBeaconsInRegion(new Region("myRangingUniqueId", null, null, null));
}
catch(RemoteException e)
{
notificar("Error", e.getMessage());
Log.e("RangingService", "Error while starting scanning: "+e.getMessage());
}
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
Log.d("RangingService", "Entering onBind");
return null;
}
The Service is already in my manifest also. Thanks for your help.
A couple of points:
The code indicates you are using a 0.x version of the Android iBeacon Library. If you are starting a new project, I would strongly recommend you use the Android Beacon Library 2.0, as the earlier library is no longer actively maintained, and it is now hard to find documentation for it.
Regardless of the library version you are using, you should be able to get a callback to the onBeaconServiceConnect() method after you bind to the BeaconManager. The fact that you don't get this callback probably indicates that the BeaconService is not starting up properly.
The most likely reason that the BeaconService is not starting up properly is because it is not properly declared in the manifest. If you are using Eclipse, you must edit your project.properties file and add the line: manifestmerger.enabled=true. If you are using AndroidStudio, this is not necessary. If you are using IntelliJ, you may have to declare the service manually.
You can verify if the manifest has the proper entries by looking at the generated manifest file in bin/AndroidManifest.xml, and verifying it has an entry for the BeaconService.
I had faced similar issues. Got resolved by doing following things
In eclipse project.properties added manifestmerger.enabled=true
restarted the eclipse
uninstalled other beacon apps in my android phone and restarted the phone
I'm making an app that takes commands from User and write it in real time. What would be the Best option for me to take? Third Party software like sphinx or should I use the built in (android speech recognition)?
Secondly I want it to write in real time, like when I speak it starts writing?
You should use the built in Android Speech recognition. Specifically, you will need to operate the SpeechRecognier API so that there is no popup dialog box.
Also, do not expect SpeechRecognizer to return anything within onPartialResults(). It rarely does.
You could try to use Sphinx, but it seems other developers have difficulty getting it to run on Android. That said, sphinx will be your only option if you want your app to run without an internet connection.
Here is a snipped of code you will need to use SpeechRecognizer:
public void recognizeDirectly(Intent recognizerIntent)
{
// SpeechRecognizer requires EXTRA_CALLING_PACKAGE, so add if it's not
// here
if (!recognizerIntent.hasExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE))
{
recognizerIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE,
"com.dummy");
}
SpeechRecognizer recognizer = getSpeechRecognizer();
recognizer.startListening(recognizerIntent);
}
#Override
public void onResults(Bundle results)
{
Log.d(TAG, "full results");
receiveResults(results);
}
#Override
public void onPartialResults(Bundle partialResults)
{
Log.d(TAG, "partial results");
receiveResults(partialResults);
}
/**
* common method to process any results bundle from {#link SpeechRecognizer}
*/
private void receiveResults(Bundle results)
{
if ((results != null)
&& results.containsKey(SpeechRecognizer.RESULTS_RECOGNITION))
{
List<String> heard =
results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
float[] scores =
results.getFloatArray(SpeechRecognizer.CONFIDENCE_SCORES);
receiveWhatWasHeard(heard, scores);
}
}
#Override
public void onError(int errorCode)
{
recognitionFailure(errorCode);
}
/**
* stop the speech recognizer
*/
#Override
protected void onPause()
{
if (getSpeechRecognizer() != null)
{
getSpeechRecognizer().stopListening();
getSpeechRecognizer().cancel();
getSpeechRecognizer().destroy();
}
super.onPause();
}
/**
* lazy initialize the speech recognizer
*/
private SpeechRecognizer getSpeechRecognizer()
{
if (recognizer == null)
{
recognizer = SpeechRecognizer.createSpeechRecognizer(this);
recognizer.setRecognitionListener(this);
}
return recognizer;
}
// other unused methods from RecognitionListener...
#Override
public void onReadyForSpeech(Bundle params)
{
Log.d(TAG, "ready for speech " + params);
}
#Override
public void onEndOfSpeech()
{
}
gregm is right but the main "write in real time" part of the question wasn't answered. You need to add an extra to indicate that you are interested in getting parts of the result back:
Adding the extra to the intent works for me
intent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true);
Warning: Partial does not return only new stuff but also the previous one. So you need to implement a check for the differences by yourself...