Android : how to detect language has been changes on phone setting - android

how could i detect if my phone language has been changed, like facebook application that will give us announce : please wait, we preparing your language
i used myString = Locale.getDefault().getDisplayLanguage();in my onCreate()
on my onCreate()
#Override
public void onCreate(Bundle savedInstanceState) {
String myString = Locale.getDefault().getDisplayLanguage();
if(myString.equals("en"){
ProgressDialog progressDialog = new ProgressDialog(getApplicationContext());
progressDialog.setMessage("Please wait, we preparing your language");
progressDialog.show();
/*
it will dismiss until the language has been prepared
*/
}else{
//do nothing
}
}
}
please give me suggestion, i still learning, will try harder. thank you.

You can use: ACTION_LOCALE_CHANGED
Here an example:
private BroadcastReceiver mLangReceiver = null;
protected BroadcastReceiver setupLangReceiver(){
if(mLangReceiver == null) {
mLangReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// do what you want
}
};
IntentFilter filter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
registerReceiver(mLangReceiver, filter);
}
return mLangReceiver;
}

What about to make a broadcast listener to: ACTION_LOCALE_CHANGED
Since "Locale represents a language/country/variant combination. Locales are used to alter the presentation of information such as numbers or dates to suit the conventions in the region they describe."
http://developer.android.com/reference/java/util/Locale.html

Locale.getDefault().getLanguage();
You can use this to get languages in "en"-like format.
Locale.getDefault().getDisplayLanguage(); returns language name e.g. "English" not "en".
This is also useful : https://stackoverflow.com/a/34265899/5515972

Here's a more modern way to get locale changes using Flow. Like others mentioned, we'll need a BroadcastReceiver to receive the Intent.ACTION_LOCALE_CHANGED action. To start, add this function to create the Flow.
private fun getLocaleChangedFlow(context: Context) = callbackFlow {
val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent) {
if (intent.action == Intent.ACTION_LOCALE_CHANGED) {
val locale = context?.resources?.configuration?.locales?.get(0)
if (locale != null) {
trySend(locale)
}
}
}
}
context.registerReceiver(receiver, IntentFilter(Intent.ACTION_LOCALE_CHANGED))
awaitClose {
context.unregisterReceiver(receiver)
}
}
Then use the Flow. Replace the TODO() with your own logic:
getLocaleChangedFlow(context)
.onEach {
TODO() // Locale changed, add code here
}
.launchIn(coroutineScope)
To learn more, see these links:
Kotlin docs about callbackFlow
Android docs for Intent.ACTION_LOCALE_CHANGED
StackOverflow answer to Wrap a BroadcastReceiver in a Flow

Related

How to use Wifimanager.LocalOnlyHotspotCallback in Xamarin.Forms

the environment is Xamarin.forms in android,
but there are no Information about this.
how can i get WifiConfiguration from callback.onstarted ?
OR can i WifiManager.LocalOnlyHotspotReservation get value from callback.onstarted ?
please check below code, the code is about to using wifi AP over oreo version
when java code, i refer this article
a link
private WifiManager wifiManager;
private WifiManager.LocalOnlyHotspotReservation reservation;
void SetHotSpot()
{
wifiManager = (WifiManager)Android.App.Application.Context.GetSystemService(Context.WifiService);
WifiManager.LocalOnlyHotspotCallback callback = new WifiManager.LocalOnlyHotspotCallback();
callback.OnStarted( reservation);
wifiManager.StartLocalOnlyHotspot(callback, new Handler());
}
void getConfiguration(object sender, System.EventArgs e)
{
if (reservation != null)
{
Log.Debug("config", reservation.WifiConfiguration.Ssid);
Log.Debug("config", reservation.WifiConfiguration.NetworkId.ToString());
Log.Debug("config", reservation.WifiConfiguration.PreSharedKey);
Log.Debug("config", reservation.WifiConfiguration.Bssid);
}
}
but when i click button, reservation is null. so Log Dose not output anything.
I converted the Java code here and came up with the following solution which seems to be working kindly take a look and let me know whether or not it works for you.
Add a Callback class that inherits from WifiManager.LocalOnlyHotspotCallback and pass the Activity in my case it is the MainActivity.
public class OreoWifiManagerCallback : WifiManager.LocalOnlyHotspotCallback
{
private const string TAG = nameof(OreoWifiManagerCallback);
private MainActivity mainActivity;
public OreoWifiManager(Activity _activity)
{
if (_activity.GetType() == typeof(MainActivity))
mainActivity = (MainActivity)_activity;
}
public override void OnStarted(WifiManager.LocalOnlyHotspotReservation reservation)
{
base.OnStarted(reservation);
Log.Debug(TAG, "Wifi Hotspot is on now");
mainActivity.mReservation = reservation;
}
public override void OnFailed([GeneratedEnum] LocalOnlyHotspotCallbackErrorCode reason)
{
base.OnFailed(reason);
Log.Debug(TAG, "onStopped: ");
}
public override void OnStopped()
{
base.OnStopped();
Log.Debug(TAG, "onFailed: ");
}
}
Then add a property in the MainActivity to keep track of the reservations
public WifiManager.LocalOnlyHotspotReservation mReservation { get; set; }
And then use these methods to turn on or off wifi in that Activity, also note that you can have a global field for wifi manager if needed.
private void TurnOnHotspot()
{
var WifiManager = (WifiManager)this.Application.GetSystemService(Android.Content.Context.WifiService);
WifiManager.StartLocalOnlyHotspot(new OreoWifiManagerCallback(this), new Handler());
}
private void TurnOffHotspot()
{
if (mReservation != null)
{
mReservation.Close();
}
}
Good luck
Feel free to revert at any time

Answering a Whatsapp video call programmatically

Is there a way to auto answer whatsapp video call using AccessibilityService in Android?
OR is there a way to stimulate a click on headset's/bluetooth's call answering button? How can i get the id of the answering button?? to perform a click with accessibility service
I know that starting from Android 8.0 Oreo we have ANSWER_PHONE_CALLS permission, but for my project i want to use an old device for remote monitoring.
Any help would be appreciated!
----- Update: Thanks to the answer of Mr. hemisphire and Mr. Kahbazi, the app is able to answer the call,but needs to be a system app to work! is there any way to make it work without being a system app? without the headset's button hack?
public class AnswerCall extends AccessibilityService {
#Override
public void onAccessibilityEvent( AccessibilityEvent event )
{
if(event.getEventType() == TYPE_WINDOW_CONTENT_CHANGED)
{
if(event.getPackageName().equals("com.whatsapp"))
{
Thread thread = new Thread() {
#Override
public void run() {
try {
while(true) {
Instrumentation inst = new Instrumentation();
inst.sendKeyDownUpSync(KeyEvent.KEYCODE_HEADSETHOOK);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
StringBuilder sb = new StringBuilder();
List<CharSequence> texts = event.getText();
if (!texts.isEmpty())
{
for (CharSequence s : event.getText()) {
sb.append(s);
}
if(sb.toString().equals("Incoming video call"))
Log.d( "onAccessibilityEvent", "whatsapp video call" );
}
}
}
}
#Override
public void onInterrupt() {
}
}
I don't think you can do what you want. Using the AccessibilityService you can know when the video call comes in:
#Override
public void onAccessibilityEvent( AccessibilityEvent event )
{
if(event.getEventType() == AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED)
{
if(event.getPackageName().equals("com.whatsapp"))
{
StringBuilder sb = new StringBuilder();
List<CharSequence> texts = event.getText();
if (!texts.isEmpty())
{
for (CharSequence s : event.getText())
{
sb.append(s);
}
if(sb.toString().equals("Incoming video call"))
{
Log.d( "onAccessibilityEvent", "whatsapp video call" );
}
}
}
}
}
However, I've never been able to answer the call programmatically. The question at How can incoming calls be answered programmatically in Android 5.0 (Lollipop)? does a great job of enumerating all possible options, but most require root and/or being a system app.
You can use sendKeyDownUpSync method from Instrumentation class.
Instrumentation inst = new Instrumentation();
inst.sendKeyDownUpSync(KeyEvent.KEYCODE_HEADSETHOOK);
if this code didn't work, try to use another KeyEvent to find the correct one.
You can see the list of KeyEvent from this link : https://developer.android.com/reference/android/view/KeyEvent.html
You can check more info in from here : Instrumentation
A classic way to achieve this is to observe notifications using the NotificationListenerService and act on the relevant action of the notification.

Cast custom channel callback never called

I'm working on an Android app that communicates with a Cast receiver app.
Connecting to the app works (I can see the app appear on the tv), but I'm having difficulties getting the custom channel to work.
In the onCreate of my Activity I get the CastContext and add my SessionManagerLister.
mCastContext = CastContext.getSharedInstance(this);
mCastContext.getSessionManager().addSessionManagerListener(getSessionManagerListener(), CastSession.class);
getSessionManagerListener() returns the listener where I register my MessageReceivedCallback:
private SessionManagerListener<CastSession> getSessionManagerListener()
{
return new SessionManagerListener<CastSession>()
{
#Override
public void onSessionStarted(CastSession castSession, String s)
{
try
{
castSession.setMessageReceivedCallbacks("urn:x-cast:be.myappname.player.cast.v1", new Cast.MessageReceivedCallback()
{
#Override
public void onMessageReceived(CastDevice castDevice, String s, String s1)
{
System.out.println("never reaches this callback");
}
});
}
catch (IOException e)
{
e.printStackTrace();
}
}
... other methods omitted ...
}
}
When I tap the Toolbar cast button I can select a device, which triggers the onSessionStarted in the SessionManagerListener (this also starts the receiver app on the tv). I then add the MessageReceivedCallback, but its callback never gets called.
Inspecting my Cast device in Chrome does show the data I'm expecting to receive, it just never seems to reach my Android code.
cast_receiver.js:67 [667.202s] [cast.receiver.IpcChannel] IPC message
[667.202s] [cast.receiver.IpcChannel] IPC message sent: {"namespace":"urn:x-cast:be.myappname.player.cast.v1","senderId":"7c442884-74e6-a388-243c-58b4ab3a4527.3471:com.google.sample.cast.refplayer.tutorial-512","data":"{\"type\":\"login request\"}"}
A colleague is working on the iOS app and that one does receive the callback.
Try the following in onSessionStarted
CastContext cc = CastContext.getSharedInstance(this);
SessionManager sm = cc.getSessionManager();
if (sm != null) {
CastSession cs = sm.getCurrentCastSession();
if (cs != null) {
try {
MyCastChannel mcc = new MyCastChannel();
cs.setMessageReceivedCallbacks("urn:x-cast:be.myappname.player.cast.v1",mcc);
}
catch (IOException e) {
}
}
}
public class MyCastChannel implements Cast.MessageReceivedCallback
{
#Override
public void onMessageReceived(CastDevice castDevice, String namespace, String message)
{
// do your thing
}
}
I had the same problem, this is how I managed to get the message to be sent:
context.sendCustomMessage(namespace, undefined, JSON.stringify({
"a": "b"
}));
This is the javascript on the receiver side. So you need the "undefined" param and also use JSON.stringify(), otherwise the message gets silently dropped.
The undefined means "send to all", but you should probably specify sender-id there.
This is in the v3 API.
In my case, it was more subtle.
The callback worked absolutely fine when the cast session was initiated for the first time. When the user presses the cast button the receiver is registered for the message callback.
override fun onSessionStarted(castSession: CastSession?, p1: String?) {
liveViewModel.requestPause()
castSession?.let {
setCastChannelReceiver(it, this#myActivity)
loadRemoteMedia(it, buildChromeCastInfo())
}
}
fun setCastChannelReceiver(castSession: CastSession?, receiver: CastMessageReceiver) {
castSession?.let {
castChannel.addReceiver(receiver, castSession)
it.setMessageReceivedCallbacks(castChannel.nameSpace, castChannel)
}
}
Although when the user use to kill the Activity which initiated the cast session and then after traversing other parts of app use to again visit the Activity, the callback failed to work.
Remember, when the user visits the Activity for the second time, the CastSession is already connected. As a result the onSessionStarted(castSession: CastSession, p1: String) method is never called.
I was under the assumption that once the receiver has been registered for the session, it need not be registered again. But still for some reason the callback never worked.
As a final resort, just to be assured I re-registered the receiver in the OnCreate() of the Activity.
override fun onCreate(out:Bundle){
....
setCastChannelReceiver(castSession, receiver)
....
}
fun setCastChannelReceiver(castSession: CastSession?, receiver: CastMessageReceiver) {
castSession?.let {
castChannel.addReceiver(receiver, castSession)
it.setMessageReceivedCallbacks(castChannel.nameSpace, castChannel)
}
}
And it worked!!
NOTE: For me, the communication between the Sender(Android App) and Cast Receiver only occurred when the string messages were in JSON format.

Get Current Activity from Google Fit API Android

I am working on demo application to get current activity sample using Google Fit. I can get Speed as well as Distance correctly. But it is not returning "in_vehicle" or "biking" state very frequently though I was in the same state. Find attached screenshot for the same. I got speed 59.40KM/H(36.91 M/h) and at that time it not returned "in_vehicle" activity state.
Please provide solution/feedback for the same.
Code :
#Override
public void onDataPoint(DataPoint dataPoint) {
for (Field field : dataPoint.getDataType().getFields()) {
Value val = dataPoint.getValue(field);
if(field.getName().trim().toLowerCase().equals("activity"))
{
if(FitnessActivities.getName(Integer.parseInt(val.toString())).equals("biking"))
{
strState = "Cycling";
}
else if(FitnessActivities.getName(Integer.parseInt(val.toString())).equals("in_vehicle"))
{
strState = "Automotive";
}
else if(FitnessActivities.getName(Integer.parseInt(val.toString())).equals("walking"))
{
strState = "Walking";
}
else
{
strState = "Not Moving";
}
}
}
}
Thanks.
You can find the sample project I created here.
https://github.com/cyfung/ActivityRecognitionSample
Important note: you may NOT get the data as frequent as you requested!
Beginning in API 21, activities may be received less frequently than
the detectionIntervalMillis parameter if the device is in power save
mode and the screen is off.
Key components:
Create the GoogleApiClient in onCreate
mGoogleApiClient =
new GoogleApiClient.Builder(this).addApi(ActivityRecognition.API)
.addConnectionCallbacks(this).addOnConnectionFailedListener(this).build();
Connect and disconnect the api client in onStart and onStop as suggested in Google Api documentation.
#Override
protected void onStart() {
super.onStart();
mGoogleApiClient.connect();
mStatusView.setText("connecting");
}
#Override
protected void onStop() {
super.onStop();
mGoogleApiClient.disconnect();
mStatusView.setText("disconnected");
}
Start activity recognition (should not be called before Google Api connect). Use PendingIntent.getService to create pending intent as callback.
final PendingResult<Status>
statusPendingResult =
ActivityRecognition.ActivityRecognitionApi
.requestActivityUpdates(mGoogleApiClient, DETECT_INTERVAL, PendingIntent
.getService(this, 0, new Intent(this, ActivityDetectionService.class),
PendingIntent.FLAG_UPDATE_CURRENT));
statusPendingResult.setResultCallback(this);
IntentService is the standard method suggested to for callback
public class ActivityDetectionService extends IntentService {
protected static final String TAG = "activityDetectionService";
public ActivityDetectionService() {
super(TAG);
}
#Override
protected void onHandleIntent(Intent intent) {
final ActivityRecognitionResult
activityRecognitionResult =
ActivityRecognitionResult.extractResult(intent);
if (activityRecognitionResult == null) {
return;
}
//process the result here, pass the data needed to the broadcast
// e.g. you may want to use activityRecognitionResult.getMostProbableActivity(); instead
final List<DetectedActivity>
probableActivities =
activityRecognitionResult.getProbableActivities();
sendBroadcast(MainActivity.newBroadcastIntent(probableActivities));
}
}
Register the service in manifest.
<service
android:name=".ActivityDetectionService"
android:exported="false">
</service>
To use the API, you need add the followings in manifest as well.
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION"/>
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
To get back the data to the activity I used a BroadcastReceiver created in onCreate
mBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
...
}
}
Register and unregister in onResume and onPause respectively.
#Override
protected void onResume() {
super.onResume();
registerReceiver(mBroadcastReceiver, newBroadcastIntentFilter());
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(mBroadcastReceiver);
}
As you said you are getting speed correctly. You can put customise code written below.
if (strState.equals("Automotive") && speed == 0.00)
{
   strState = "Not Moving";
}
else if (strState.equals("Not Moving") && speed > 5)
{
   strState = "Automotive";
}
else
{
   strState = "strState";
}
This might not be the correct one but It will be give you nearby state result.
I'm not familiar with google fit api, so the only advice i can give you is to check your code carefully. Is
Integer.parseInt(val.toString())
returning the right int and can
FitnessActivities.getName()
equal "biking", "walking", "in_vehicle" etc.
As i can see from here: https://developers.google.com/fit/rest/v1/reference/activity-types
Biking, In vehicle and Walking are 0, 1 and 7.
Check what FitnessActivities.getName(0) is returning for example, also check is val returning different values or it's returning the same every time.
If you have any problem with your codes you should know what are the code is doing at any line, what methods and functions are returning... Also inform people so they found solutions easier.

Speech recognition supported languages on Android

I'm having a problem getting the supported languages. I have seen a solution
that is to create a Broadcast receiver and fill the list with the languages.
public class LanguageChecker extends BroadcastReceiver
{
private List<String> supportedLanguages;
private String languagePreference;
#Override
public void onReceive(Context context, Intent intent)
{
//Log.d(Constants.Tag,"OnReceive");
Bundle results = getResultExtras(true);
if (results.containsKey(RecognizerIntent.EXTRA_LANGUAGE_PREFERENCE))
{
languagePreference =
results.getString(RecognizerIntent.EXTRA_LANGUAGE_PREFERENCE);
}
if (results.containsKey(RecognizerIntent.EXTRA_SUPPORTED_LANGUAGES))
{
supportedLanguages =
results.getStringArrayList(
RecognizerIntent.EXTRA_SUPPORTED_LANGUAGES);
}
}
public List<String> getSupportedLanguages() {
return supportedLanguages;
}
}
but the problem is that I need this supportedLanguages list to fill my spinner.
When I call the method getSupportedLanguages, I get null.
This is how I use the broadcast within onCreate:
try {
lang = new LanguageChecker();
Intent detailsIntent = new Intent(RecognizerIntent.ACTION_GET_LANGUAGE_DETAILS);
sendOrderedBroadcast(detailsIntent, null, lang, null, Activity.RESULT_OK, null, null);
supportedLanguagesForSpeech=lang.getSupportedLanguages();
Log.d(Constants.Tag, String.valueOf(supportedLanguagesForSpeech.size()));
}
catch (Exception e){
Log.d(Constants.Tag,e.getMessage());
}
You should solve it with a callback to make sure that supportedLanguages is assigned. You are getting null because you are not waiting onReceive to be called.
Here is my current solution to querying all the available speech recognition services for their supported languages:
https://github.com/Kaljurand/K6nele/blob/3e514edc87e07babb0be57fa31ab48be7e2226e7/app/src/ee/ioc/phon/android/speak/RecognitionServiceManager.java
You can see it in action in the Kõnele app (http://kaljurand.github.io/K6nele/about/), in the "Settings -> Recognition languages & services" list.

Categories

Resources