Offline Speech Recognition In Android (JellyBean) - android

It looks as though Google has made offline speech recognition available from Google Now for third-party apps. It is being used by the app named Utter.
Has anyone seen any implementations of how to do simple voice commands with this offline speech rec? Do you just use the regular SpeechRecognizer API and it works automatically?

Google did quietly enable offline recognition in that Search update, but there is (as yet) no API or additional parameters available within the SpeechRecognizer class. {See Edit at the bottom of this post} The functionality is available with no additional coding, however the user’s device will need to be configured correctly for it to begin working and this is where the problem lies and I would imagine why a lot of developers assume they are ‘missing something’.
Also, Google have restricted certain Jelly Bean devices from using the offline recognition due to hardware constraints. Which devices this applies to is not documented, in fact, nothing is documented, so configuring the capabilities for the user has proved to be a matter of trial and error (for them). It works for some straight away – For those that it doesn't, this is the ‘guide’ I supply them with.
Make sure the default Android Voice Recogniser is set to Google not
Samsung/Vlingo
Uninstall any offline recognition files you already have installed
from the Google Voice Search Settings
Go to your Android Application Settings and see if you can uninstall
the updates for the Google Search and Google Voice Search
applications.
If you can't do the above, go to the Play Store see if you have the
option there.
Reboot (if you achieved 2, 3 or 4)
Update Google Search and Google Voice Search from the Play Store (if
you achieved 3 or 4 or if an update is available anyway).
Reboot (if you achieved 6)
Install English UK offline language files
Reboot
Use utter! with a connection
Switch to aeroplane mode and give it a try
Once it is working, the offline recognition of other languages,
such as English US should start working too.
EDIT: Temporarily changing the device locale to English UK also seems to kickstart this to work for some.
Some users reported they still had to reboot a number of times before it would begin working, but they all get there eventually, often inexplicably to what was the trigger, the key to which are inside the Google Search APK, so not in the public domain or part of AOSP.
From what I can establish, Google tests the availability of a connection prior to deciding whether to use offline or online recognition. If a connection is available initially but is lost prior to the response, Google will supply a connection error, it won’t fall-back to offline. As a side note, if a request for the network synthesised voice has been made, there is no error supplied it if fails – You get silence.
The Google Search update enabled no additional features in Google Now and in fact if you try to use it with no internet connection, it will error. I mention this as I wondered if the ability would be withdrawn as quietly as it appeared and therefore shouldn't be relied upon in production.
If you intend to start using the SpeechRecognizer class, be warned, there is a pretty major bug associated with it, which require your own implementation to handle.
Not being able to specifically request offline = true, makes controlling this feature impossible without manipulating the data connection. Rubbish. You’ll get hundreds of user emails asking you why you haven’t enabled something so simple!
EDIT: Since API level 23 a new parameter has been added EXTRA_PREFER_OFFLINE which the Google recognition service does appear to adhere to.
Hope the above helps.

I would like to improve the guide that the answer https://stackoverflow.com/a/17674655/2987828 sends to its users, with images. It is the sentence "For those that it doesn't, this is the ‘guide’ I supply them with." that I want to improve.
The user should click on the four buttons highlighted in blue in these images:
Then the user can select any desired languages. When the download is done, he should disconnect from network, and then click on the "microphone" button of the keyboard.
It worked for me (android 4.1.2), then language recognition worked out of the box, without rebooting. I can now dictates instructions to the shell of Terminal Emulator ! And it is twice faster offline than online, on a padfone 2 from ASUS.
These images are licensed under cc by-sa 3.0 with attribution required to stackoverflow.com/a/21329845/2987828 ; you may hence add these images anywhere along with this attribution.
(This the standard policy of all images and texts at stackoverflow.com)

A simple and flexible offline recognition on Android is implemented by CMUSphinx, an open source speech recognition toolkit. It works purely offline, fast and configurable It can listen continuously for keyword, for example.
You can find latest code and tutorial here.
Update in 2019: Time goes fast, CMUSphinx is not that accurate anymore. I recommend to try Kaldi toolkit instead. The demo is here.

In short, I don't have the implementation, but the explanation.
Google did not make offline speech recognition available to third party apps. Offline recognition is only accessable via the keyboard. Ben Randall (the developer of utter!) explains his workaround in an article at Android Police:
I had implemented my own keyboard and was switching between Google
Voice Typing and the users default keyboard with an invisible edit
text field and transparent Activity to get the input. Dirty hack!
This was the only way to do it, as offline Voice Typing could only be
triggered by an IME or a system application (that was my root hack) .
The other type of recognition API … didn't trigger it and just failed
with a server error. … A lot of work wasted for me on the workaround!
But at least I was ready for the implementation...
From Utter! Claims To Be The First Non-IME App To Utilize Offline Voice Recognition In Jelly Bean

I successfully implemented my Speech-Service with offline capabilities by using onPartialResults when offline and onResults when online.

I was dealing with this and I noticed that you need to install the offline package for your Language. My language setting was "Español (Estados Unidos)" but there is not offline package for that language, so when I turned off all network connectivity I was getting an alert from RecognizerIntent saying that can't reach Google, then I change the language to "English (US)" (because I already have the offline package) and launched the RecognizerIntent it just worked out.
Keys: Language setting == Offline Voice Recognizer Package

It is apparently possible to manually install offline voice recognition by downloading the files directly and installing them in the right locations manually. I guess this is just a way to bypass Google hardware requirements.
However, personally I didn't have to reboot or anything, simply changing to UK and back again did it.

Working example is given below,
MyService.class
public class MyService extends Service implements SpeechDelegate, Speech.stopDueToDelay {
public static SpeechDelegate delegate;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//TODO do something useful
try {
if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
((AudioManager) Objects.requireNonNull(
getSystemService(Context.AUDIO_SERVICE))).setStreamMute(AudioManager.STREAM_SYSTEM, true);
}
} catch (Exception e) {
e.printStackTrace();
}
Speech.init(this);
delegate = this;
Speech.getInstance().setListener(this);
if (Speech.getInstance().isListening()) {
Speech.getInstance().stopListening();
} else {
System.setProperty("rx.unsafe-disable", "True");
RxPermissions.getInstance(this).request(permission.RECORD_AUDIO).subscribe(granted -> {
if (granted) { // Always true pre-M
try {
Speech.getInstance().stopTextToSpeech();
Speech.getInstance().startListening(null, this);
} catch (SpeechRecognitionNotAvailable exc) {
//showSpeechNotSupportedDialog();
} catch (GoogleVoiceTypingDisabledException exc) {
//showEnableGoogleVoiceTyping();
}
} else {
Toast.makeText(this, R.string.permission_required, Toast.LENGTH_LONG).show();
}
});
}
return Service.START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
//TODO for communication return IBinder implementation
return null;
}
#Override
public void onStartOfSpeech() {
}
#Override
public void onSpeechRmsChanged(float value) {
}
#Override
public void onSpeechPartialResults(List<String> results) {
for (String partial : results) {
Log.d("Result", partial+"");
}
}
#Override
public void onSpeechResult(String result) {
Log.d("Result", result+"");
if (!TextUtils.isEmpty(result)) {
Toast.makeText(this, result, Toast.LENGTH_SHORT).show();
}
}
#Override
public void onSpecifiedCommandPronounced(String event) {
try {
if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
((AudioManager) Objects.requireNonNull(
getSystemService(Context.AUDIO_SERVICE))).setStreamMute(AudioManager.STREAM_SYSTEM, true);
}
} catch (Exception e) {
e.printStackTrace();
}
if (Speech.getInstance().isListening()) {
Speech.getInstance().stopListening();
} else {
RxPermissions.getInstance(this).request(permission.RECORD_AUDIO).subscribe(granted -> {
if (granted) { // Always true pre-M
try {
Speech.getInstance().stopTextToSpeech();
Speech.getInstance().startListening(null, this);
} catch (SpeechRecognitionNotAvailable exc) {
//showSpeechNotSupportedDialog();
} catch (GoogleVoiceTypingDisabledException exc) {
//showEnableGoogleVoiceTyping();
}
} else {
Toast.makeText(this, R.string.permission_required, Toast.LENGTH_LONG).show();
}
});
}
}
#Override
public void onTaskRemoved(Intent rootIntent) {
//Restarting the service if it is removed.
PendingIntent service =
PendingIntent.getService(getApplicationContext(), new Random().nextInt(),
new Intent(getApplicationContext(), MyService.class), PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
assert alarmManager != null;
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1000, service);
super.onTaskRemoved(rootIntent);
}
}
For more details,
https://github.com/sachinvarma/Speech-Recognizer
Hope this will help someone in future.

Related

Can we guarantee that Android's SpeechRecognizer does not send data to Google?

I'm trying to implement Android's SpeechRecognizer feature. Due to privacy constraints of my company, the data must explicitly not leave the device.
So far:
I've implemented the SpeechRecognizer class by using the SpeechRecognizer.createSpeechRecognizermethod. When I tried it without internet, it just worked fine!
However, there's not guarantee as far as I see that Google won't send the data when online, if not for transcription, then for improving their Audio training data..
SpeechRecognizer.createOnDeviceSpeechRecognizer - This is available from Android 12 and on. Let's say I don't mind. However, it only works in specific devices, ie. Pixel 6 but not even in Pixel 4a.
putExtra(RecognizerIntent.EXTRA_PREFER_OFFLINE, true) - This didn't work either. It keeps giving me the error: ERROR_NO_MATCH, in any device that I've tried.
So that leaves us with plain SpeechRecognizer.createSpeechRecognizer and my implementation is like this:
var recognizerIntent: Intent? = null
if (SpeechRecognizer.isRecognitionAvailable(applicationContext)) {
sr = SpeechRecognizer.createSpeechRecognizer(applicationContext)
val listener = MySpeechRecognitionListener(scopeProvider, lifecycleScope, {
...
}
sr.setRecognitionListener(listener)
recognizerIntent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH).apply {
putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_WEB_SEARCH)
}
sr.startListening(recognizerIntent)
} else {...}
Question:
Can we somehow guarantee that Android's SpeechRecognizer does not send data to Google?
Use:
public static SpeechRecognizer createSpeechRecognizer (Context context,
ComponentName serviceComponent)
specifying a serviceComponent that is open source, so that you can verify that it does not send data to Google.
I don't see any other solution, i.e. I'm not aware of any Android API flags like DONT_SEND_DATA_TO_GOOGLE.
you could ensure that internet connection (wifi, cell network, etc) is disabled during the recognizing however that does not guarantee that the recognized speech isn't recorded/cached and sent to google later when there is a network connection.

how to disable the question (Do you want to ignore battery optimization?) android studio

I was having problem whit android media player because when I turn off the screen the system goes to sleep mode and stop it and I didnt want that because nobody wants to listen music and have the screen on (who do that?).
I noticed that the problem was on the battery optimizations because if the mobile was plug to power cable it keeps the music playin even if it goes to sleep mode.
I tried with a lot of posibilities to fix it (reading android documentation and trying every thing I was finding in the net) but what works was this code:
public void doPower() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
String packageName = getActivity().getPackageName();
PowerManager pm = (PowerManager) getActivity().getSystemService(Context.POWER_SERVICE);
if (!pm.isIgnoringBatteryOptimizations(packageName)) {
try {
//some device doesn't has activity to handle this intent
//so add try catch
Intent intent = new Intent();
intent.setAction(android.provider.Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" + packageName));
startActivity(intent);
} catch (Exception e) {
}
}
}
}
The problem here is: The app at the beginning shows an alert asking the user to disable the battery optimizations and I dont want that, because some users may thinks "this is a bad thing" or "why its asking this?" Because an app like spotify doesnt do it.
How can I avoid the alert message? If I cant, how can I add something else to the message? (something like this: "So you will able to listen the radio with the screen turn off")
Thanks in advance and best regards.
You can't avoid that dialog and asking to avoid battery optimizations is absolutely not needed.
What is needed is a wakelock, as described in the MediaPlayer Using wake locks documentation:
When designing applications that play media in the background, the device may go to sleep while your service is running. Because the Android system tries to conserve battery while the device is sleeping, the system tries to shut off any of the phone's features that are not necessary, including the CPU and the WiFi hardware. However, if your service is playing or streaming music, you want to prevent the system from interfering with your playback.
In order to ensure that your service continues to run under those conditions, you have to use "wake locks." A wake lock is a way to signal to the system that your application is using some feature that should stay available even if the phone is idle.
If you're using MediaPlayer, this only requires you use the setWakeMode() method:
mMediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
(Note the additional note on the documentation page about holding a wifi lock if you're streaming your media from the network.)

Install referrer not working in some redmi devices

I need to track install referrals for my android app. It's working fine in most of the devices. But in Redmi device, the broadcast is not getting triggered. I tested it with Redmi Note 4
I have tested it both from via ADB as well as play store. Both don't trigger the broadcast in Redmi device
Below is the code that I am using
public class ReferrerReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("Broadcast", "RECEIVED!");
}
}
<receiver
android:name=".receiver.ReferrerReceiver"
android:exported="true">
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER"/>
</intent-filter>
</receiver>
Please suggest if someone faced the same issue and got some solution??
Is your app in the list of "protected apps" that are allowed to run in the background? If not, it won't get automatically started. This is a problem on devices like Xiaomi, Huawei and others. There should be a settings page in "Settings->Apps-Security" that allows you to add your app to a list of apps that are allowed to autostart, run in the background, etc. Each device manufacturer does this a bit differently, but in general we see this on Chinese devices as a way to preserve battery life.
See also:
How to get MIUI Security app auto start permission programmatically?
How to enable AutoStart option for my App in Xiaomi phone Security App programmatically in android
GCM push notifications for android devices are not working on MI and Letv mobiles
In Redmi device some android applications needs permissions. Please allow the permissions manually in the device. By using app permissions option in your device give all permissions. It may work which i had observed for my app.
There is always some issues with the miui due to their restrictions on background processes you can turn them on here is how it goes
1: Go to settings --> manage apps' battery usage --> choose apps. From there, pick all the apps you want to receive push notifications and select "No restrictions."
2: Go to settings --> permissions --> autostart. From there, pick the apps you want, and toggle the switch to turn it on.
3: Lock the app in the "recent apps"/ "app overview" plane. Do so by first opening the apps, then press the "recent apps/overview button" (that's the square button on stock Android, or the button with three horizontal lines on the Mi Mix). From there, find the app you want to receive notifications, pull down on it to "lock it", so it never gets cleared.
4: This last step requires Developer Options privileges. To enable that, go to settings (man... I'm getting tired of typing "go to settings" ...) --> about phone
tap on MIUI version tab like eight times. You should then get a little message saying "you are now a developer." Then head back out to settings, go to developer option, scroll to nearly the bottom, find "memory optimization," and turn it off.
Again, maybe step 4 is all you need.
I use Redmi 3 Pro and always have trouble with Android Permission. Xiaomi devices use custom ROM that caused permission request buggy sometimes.
The overlay service permission is always forced set to Denied in every app that I installed. I must manually Allow it.
Nice workaround I found to let Xiaomi devices auto start permission: How to get MIUI Security app auto start permission programmatically?
You could solve this issue by using the Play Install Referrer Library api 1.0 from Google. I did it this way and it works fine on devices that block the auto start by default.
First Add the following line to the dependencies section of the build.gradle file for your app:
dependencies {
...
compile 'com.android.installreferrer:installreferrer:1.0'
}
Then you should implement the interface InstallReferrerStateListener and its methods onInstallReferrerSetupFinished and onInstallReferrerServiceDisconnected in your Activity
Call the newBuilder() method to create an instance of InstallReferrerClient class.
Call the startConnection() to establish a connection to Google Play.
The startConnection() method is asynchronous, so you must override InstallReferrerStateListener to receive a callback after startConnection() completes.
You should also Override the onInstallReferrerSetupFinished() method to handle lost connections to Google Play. For example, the Play Install Referrer Library client may lose connection if the Play Store service is updating in the background. The library client must call the startConnection() method to restart the connection before making further requests.
Example:
InstallReferrerClient mReferrerClient
mReferrerClient = InstallReferrerClient.newBuilder(this).build();
mReferrerClient.startConnection(new InstallReferrerStateListener() {
#Override
public void onInstallReferrerSetupFinished(int responseCode) {
switch (responseCode) {
case InstallReferrerResponse.OK:
// Connection established
break;
case InstallReferrerResponse.FEATURE_NOT_SUPPORTED:
// API not available on the current Play Store app
break;
case InstallReferrerResponse.SERVICE_UNAVAILABLE:
// Connection could not be established
break;
}
}
#Override
public void onInstallReferrerServiceDisconnected() {
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
}
});
After you have established a connection to the Play Store app:
Use the synchronized getInstallReferrer() method to return ReferrerDetails.
Then, use methods in ReferrerDetails to get install timestamps and a referrer url.
ReferrerDetails response = mReferrerClient.getInstallReferrer();
response.getInstallReferrer();
response.getReferrerClickTimestampSeconds();
response.getInstallBeginTimestampSeconds();
For further info:
https://developer.android.com/google/play/installreferrer/library
Hope this helps!!

What is the name of GoogleTTSService in JellyBean 4.3?

In all Android versions prior to 4.3, the name of Google's text-to-speech service, belonging to package android.tts.TtsService, is GoogleTTSService.
Thus, if you inspect the list of running services in devices running Android 4.2 or lower, you will find com.google.android.tts.GoogleTTSService among them.
But in Android 4.3 that seems to have changed and, among the many services listed in my running device, I can no longer find a corresponding service name.
What is the new name?
Is it part of a different service?
Update: It appears that the package name for the service has been renamed from android.tts.TtsService in 2.x to android.speech.tts.TextToSpeech in 4.3. That's a step in the right direction but the actual name of Google's engine is still missing.
Any idea?
You can discover the package for any TTS Engine in the following way:
TextToSpeech tts = new TextToSpeech(context, onInitListener);
Then in the onInit Listener:
#Override
public void onInit(final int status) {
switch (status) {
case TextToSpeech.SUCCESS:
try {
final String initEngine = tts.getDefaultEngine();
// Output the engine to the log if it's != null
} catch (final Exception e) {
}
break;
}
}
From my experience, the engine can sometimes return null or crash when it's called too soon after onInit, so surrounding with a try/catch block is recommended. This was only happening with some IVONA and SVOX TTS engines, but of course the user could have one of those as their default.
According to this, you may be using the ACTION_CHECK_TTS_DATA intent, which is not handled correctly in Android 4.2.
Try to eliminate the use ACTION_CHECK_TTS_DATA intent and instead we just rely on the method TextToSpeech.isLanguageAvailable() as an indicator of whether or not the voice data is installed.
Additional useful information that may be related to your problem:
Access the Google Now voice using the Android TTS APIs
Offline Speech Recognition In Android (JellyBean)

LocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER) is not reliable, why?

One user of my app reported that app tells network for location is off even he did turn it on. He sent me few screen shots and they made me think;
LocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
is not working properly. His phone is running Android 4.1.2 and first I thought this is the cause of this issue. But it was not the case. He sent me a screen shot of that setting too.
Then I googled and found this. The question seems to help me but unfortunately answer was not helpful for this case and questioner did not pursue farther.
My app is related to location and have been using LocationManager.isProviderEnabled to know GPS and Network for location is on or off. I have never been told my app is not properly knowing those settings until recently. He is the first user who reported the issue. I learned there are another method to know GPS and Network for location settings, by seeing Secure.LOCATION_PROVIDERS_ALLOWED. To see how this method work on his phone, I wrote simple app and asked him to run. This app does simple task and shows text on screen.
LocationManager locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
if(locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER))
{
string = "GPS=on\n";
}
else
{
string = "GPS=off\n";
}
if(locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER))
{
string += "Network=on\n";
}
else
{
string += "Network=off\n";
}
String status = android.provider.Settings.Secure.getString(getContentResolver(), Secure.LOCATION_PROVIDERS_ALLOWED);
if(status.contains("gps"))
{
string += "GPS=on\n";
}
else
{
string += "GPS=off\n";
}
if(status.contains("network"))
{
string += "Network=on\n";
}
else
{
string += "Network=off\n";
}
He sent back screen shot again. It looks;
GPS=on
Network=off
GPS=on
Network=on
This result did not make me happy. There could be some possibilities for this.
As other person questioned before, this issue has been there on some phones.
Google broke this with 4.1.2. isProviderEnabled does not work on this version.
Although not documented, starting 4.1.2, isProviderEnabled won't work as it did before.
No, Google changed anything. This is a bug for this particular phone.
Now my questions are;
Is LocationManager.isProviderEnabled still valid for Android 4.1.2 and later?
Does seeing Secure.LOCATION_PROVIDERS_ALLOWED have some drawbacks/pit holes (when I gave up using LocationManager.isProviderEnabled?
Thanks in advance.
EDIT1:
Here you can download test app from Google Play to try or ask someone to try.
EDIT6:
I removed test app since this question is answered.
EDIT2:
I released my app which checks network provider is usable by seeing Secure.LOCATION_PROVIDERS_ALLOWED and got exception on limited phones.
These are ACRA's report.
Some phone running OS 4.1.1.
java.lang.IllegalArgumentException: requested provider network doesn't exisit
at android.os.Parcel.readException(Parcel.java:1434)
at android.os.Parcel.readException(Parcel.java:1384)
at android.location.ILocationManager$Stub$Proxy.requestLocationUpdates(ILocationManager.java:675)
at android.location.LocationManager._requestLocationUpdates(LocationManager.java:686)
at android.location.LocationManager.requestLocationUpdates(LocationManager.java:508)
Some phone running OS 4.1.2.
java.lang.IllegalArgumentException: provider=network
at android.os.Parcel.readException(Parcel.java:1439)
at android.os.Parcel.readException(Parcel.java:1389)
at android.location.ILocationManager$Stub$Proxy.requestLocationUpdates(ILocationManager.java:659)
at android.location.LocationManager._requestLocationUpdates(LocationManager.java:690)
at android.location.LocationManager.requestLocationUpdates(LocationManager.java:512)
I have never seen those exceptions until I changed a method to check network provider for location is usable or not. So I think LocationManager.isProviderEnabled is safe and seeing Secure.LOCATION_PROVIDERS_ALLOWED is risky. But this will put me back to original issue. Why LocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER) returns false (and there is not really) when Secure.LOCATION_PROVIDERS_ALLOWED tells there IS. Is Android OS poorly designed? Or I have just seeing issues tied only to specific (but there are at least 2 of them) phones?
EDIT3:
I updated test app to show GPS/Network location provider seems really usable or not by accessing with requestLocationUpdates().
And I disclose 2 phones name.
1) SBM200SH, OS4.1.2, Softbank mobile, Sharp Corporation
2) HTX21 (INFOBAR A02), OS4.1.1, KDDI, HTC
EDIT4:
I found 3rd phone.
3) SBM203SH, OS4.1.2, Softbank mobile, Sharp Corporation
EDIT5:
Sharp Corporation is running discussion space for mobile developers. I posted topic by presenting this SO's question. I hope someone at Sharp Corporation takes action for this. I will keep this updated.
Developer support provided by Sharp corporation is excellent and they answered to my question in less than 48 hours.
This is what I got from them.
There are 2 conditions must be met that LocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER) returns true.
Some internal state is ready for network location.
Network location is enabled on setting screen.
Second one is obvious. But first one is not. They told how to simulate first one is negative. You can confirm the issue with steps shown below and running my test app (please see my question for link to download).
Open settings of you phone.
Tap Applications.
Tap All tab.
Find "Network Location", tap it.
Tap "Disable".
Reboot your phone.
Run test app.
For reason I can't understand the user's phone failed to do something related to first condition shown above and exhibits the issue.
Conclusion:
LocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER) is reliable. And be aware, Secure.LOCATION_PROVIDERS_ALLOWED is less reliable.
The modern way to check the users Location settings is through LOCATION_MODE in Settings.Secure
For example if you simply want to know if the user has disabled them or not, you can do:
public static boolean isLocationEnabled(Context context) {
return getLocationMode(context) != Settings.Secure.LOCATION_MODE_OFF;
}
private static int getLocationMode(Context context) {
return Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
}
This will return true if Location is enabled. If you need finer granularity see the docs for details.
This method is better suited when using the Google Services Location APIs than the old NETWORK_PROVIDER and GPS_PROVIDER ways. Note: Requires KitKat / API19
Not directly an answer to your question(s), but check out the new Location API that Google launched last week. It's really easy to implement and it will check for the best possible location without wasting battery.
http://developer.android.com/google/play-services/location.html
and here's a session at Google I/O about this new API and how to use it.
http://www.youtube.com/watch?v=Bte_GHuxUGc
This way you don't need to worry about checking if the GPS is on or not and stuff like that
Location Manager is not reliable on some phones. You may notice that if you launch google maps all of a sudden your app works. That is because Google Maps kicked the LocationManager. Which also means that there is programmatic way to kick that dude alive. So I used
HomeScreen.getLocationManager().requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, 0, 0, new LocationListener() {
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
}
#Override
public void onLocationChanged(final Location location) {
}
});
After the above code, I called what ever I needed from LocationManager and it kinda worked. If not try out the new API's LocationClient. This is suppose to be much better, battery, accuracy and reliability.

Categories

Resources