I have implemented agent live availability according to documentation. Problem is according to documentation it would land in OnResult method but every time response is landed in OnCompleted method, where I am unable to retrieve agent status from async variable.
Please Guide me if I am missing something or how to get live agent availability from OnCompleted.
My code (called within HomeFragment)
private void setupChatButton() {
try {
// Build a configuration object
ChatConfiguration chatConfiguration =
new ChatConfiguration.Builder(ORG_ID, BUTTON_ID,
DEPLOYMENT_ID, LIVE_AGENT_POD)
.build();
// Create an agent availability client
AgentAvailabilityClient client = ChatCore.configureAgentAvailability(chatConfiguration);
// Check agent availability
client.check().onResult((async, state) -> {
switch (state.getStatus()) {
case AgentsAvailable: {
// Toast.makeText(context, "Available Chat", Toast.LENGTH_LONG).show();
isAgentAvailable = true;
fabChat.setBackgroundTintList(ContextCompat.getColorStateList(context, R.color.colorAccent));
break;
}
case NoAgentsAvailable: {
// Toast.makeText(context, "NOAGENTS Chat", Toast.LENGTH_LONG).show();
isAgentAvailable = false;
fabChat.setBackgroundTintList(ContextCompat.getColorStateList(context, R.color.grey));
break;
}
case Unknown: {
// Toast.makeText(context, "UNKNOWN Chat", Toast.LENGTH_LONG).show();
isAgentAvailable = false;
fabChat.setBackgroundTintList(ContextCompat.getColorStateList(context, R.color.grey));
break;
}
}
})
.onComplete(async -> {
Log.e("Home Fragment ", "Chat Call completed");
if (async.isComplete()) {
isAgentAvailable = true;
fabChat.setBackgroundTintList(ContextCompat.getColorStateList(context, R.color.colorAccent));
} else {
isAgentAvailable = false;
fabChat.setBackgroundTintList(ContextCompat.getColorStateList(context, R.color.grey));
}
// Toast.makeText(context, "Chat Completed!", Toast.LENGTH_LONG).show();
});
} catch (Exception e) {
Log.e(getContext().getClass().getSimpleName(), e.getMessage());
}
So turns out I was missing some dependencies in my gradle files, also the updated library versions require you to use minSDK 21 where I was using minSDK 19.
Following are the dependencies needed to support chat and preChat features:
implementation 'com.salesforce.service:chat-ui:3.1.0'
implementation 'com.salesforce.service:chat-core:3.1.0'
Apparently there are no references to it in official documentation.
Reference Agent
Reference Chat
Related
I have an Android project where I want to use com.android.billingclient.api version 4.0.0, which would replace an old billing library that google doesn't allow any more (com.anjlab.android.iab.v3). I've implemented the methods for a one-time purchase, but when querying the SKU Details with billingClient.querySkuDetailsAsync using the SKU string for the product, I get an empty result set. I've been assured that the SKU is correct, so I don't know where the error might be.
Also, the old implementation required to provide a license key, which isn't the case with the new library. Do I need to define it somewhere else in the app?
Here's the code where it fails:
List<String> skuList = new ArrayList<>();
skuList.add(SKU_ID);
SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
params.setSkusList(skuList).setType(SkuType.INAPP);
final Activity v = this;
billingClient.querySkuDetailsAsync(params.build(), new SkuDetailsResponseListener() {
#Override
public void onSkuDetailsResponse(BillingResult billingResult, List<SkuDetails> skuDetailsList) {
Has anyone a suggestion what to do?
This is how I query the SKU details within my app.
You can try to use this example and see if this works for you.
billingClient.startConnection(new BillingClientStateListener() {
#Override
public void onBillingSetupFinished(#NonNull BillingResult billingResult) {
Log.d(TAG, "Connection finished");
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
// The BillingClient is ready. You can query purchases here.
List<String> skuList = new ArrayList<> ();
skuList.add(ITEM_SKU_ADREMOVAL);
SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP);
billingClient.querySkuDetailsAsync(params.build(),
(billingResult1, skuDetailsList) -> {
// Process the result.
if (billingResult1.getResponseCode() == BillingClient.BillingResponseCode.OK && skuDetailsList != null) {
for (Object skuDetailsObject : skuDetailsList) {
skuDetails = (SkuDetails) skuDetailsObject;
String sku = skuDetails.getSku();
String price = skuDetails.getPrice();
if (ITEM_SKU_ADREMOVAL.equals(sku)) {
removeadsPrice = price;
}
else {
Log.d(TAG,"Sku is null");
}
}
Log.d(TAG, "i got response");
Log.d(TAG, String.valueOf(billingResult1.getResponseCode()));
Log.d(TAG, billingResult1.getDebugMessage());
}
else if (billingResult1.getResponseCode() == BillingClient.BillingResponseCode.ERROR) {
Toast.makeText(MainActivity.this, "Error in completing the purchase!", Toast.LENGTH_SHORT).show();
}
});
}
else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.SERVICE_TIMEOUT) {
Toast.makeText(MainActivity.this, "Service timeout!", Toast.LENGTH_SHORT).show();
}
else {
Toast.makeText(MainActivity.this, "Failed to connect to the billing client!", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onBillingServiceDisconnected() {
restartConnection();
}
});
Getting this one working properly depends on several different factors
Have you published your app to Play Console or at least to an
internal track or something?
Do you have active products or subscriptions on your Google Play
Console?
Have you configured your licensed testers?
Please see the documentation for more info.
I'm working in on an app that uses authentication from the AWS Amplify library.
I tried to check the sign-in state by looking at Amplify's auth events, but it
doesn't work. I tried to verify with logcat, but it only shows me the output of
the fetch.
Amplify.Auth.fetchAuthSession(
result -> Log.i("AmplifyQuickstart", result.toString()),
error -> Log.e("AmplifyQuickstart", error.toString())
);
Amplify.Hub.subscribe(HubChannel.AUTH, hubEvent -> {
if (hubEvent.getName().equals(InitializationStatus.SUCCEEDED.toString())) {
Log.i("AuthQuickstart", "Auth successfully initialized");
} else if (hubEvent.getName().equals(InitializationStatus.FAILED.toString())) {
Log.i("AuthQuickstart", "Auth failed to succeed");
} else {
switch (AuthChannelEventName.valueOf(hubEvent.getName())) {
case SIGNED_IN:
Log.i("AuthQuickstart", "Auth just became signed in.");
break;
case SIGNED_OUT:
Log.i("AuthQuickstart", "Auth just became signed out.");
break;
case SESSION_EXPIRED:
Log.i("AuthQuickstart", "Auth session just expired.");
break;
default:
Log.w("AuthQuickstart", "Unhandled Auth Event: " + AuthChannelEventName.valueOf(hubEvent.getName()));
break;
}
}
});
One way that I succeed to handle the problem is to pass the error lambda
reference to errorAuthenticationHandle function as follows:
Amplify.Auth.signIn(this.userName, password,
result -> Log.i("AuthQuickstart", result.isSignInComplete() ?
"Sign in succeeded" : "Sign in not complete"),
this::errorAuthenticationHandle
);
private void errorAuthenticationHandle(AuthException error) {
Log.e("AmplifyQuickstart", error.toString());
switch (getErrorNumber(error)) {
// Server require password reset
case RESET:
// Some code
break;
case FAILED:
// Some code
break;
}
}
I have a problem with Ionic (5.0.1) and Angular. I would like to visualize some java variables in the home page, the variables concern information about the localization or about some parameters of the network cells. I found an example on how to install the "Cordova AdvancedGeolocation" plugin, but I can only view the default map, actually I wish I could access the plugin's variables to display in front-end.
I use this code in app.component.ts and then I change config.xml and, finally, I put "sample-map.html" in src field.
I see the map with location gps and network, but I don't understand how I could have access to variables Java and display them in front-end.
Thanks a lot.
import { Component, NgZone } from '#angular/core';
import { Platform } from '#ionic/angular';
import { SplashScreen } from '#ionic-native/splash-screen/ngx';
import { StatusBar } from '#ionic-native/status-bar/ngx';
import { Geolocation, Geoposition } from '#ionic-native/geolocation/ngx';
#Component({
selector: 'app-root',
templateUrl: 'app.component.html'
})
export class AppComponent {
AdvancedGeolocation: any;
currentLat: any;
currentLng: any;
watch: any;
constructor(
private platform: Platform,
private splashScreen: SplashScreen,
private statusBar: StatusBar,
// tslint:disable-next-line: no-shadowed-variable
private zone : NgZone,
private geolocation: Geolocation
) {
this.initializeApp();
}
initializeApp() {
this.platform.ready().then(() => {
this.statusBar.styleDefault();
this.splashScreen.hide();
if (this.platform.is('android')) {
this.platform.ready().then(() => {
this.AdvancedGeolocation.start((success) => {
//loading.dismiss();
// this.refreshCurrentUserLocation();
try {
var jsonObject = JSON.parse(success);
console.log("Provider " + JSON.stringify(jsonObject));
switch (jsonObject.provider) {
case "gps":
console.log("setting gps ====<<>>" + jsonObject.latitude);
this.currentLat = jsonObject.latitude;
this.currentLng = jsonObject.longitude;
break;
case "network":
console.log("setting network ====<<>>" + jsonObject.latitude);
this.currentLat = jsonObject.latitude;
this.currentLng = jsonObject.longitude;
break;
case "satellite":
//TODO
break;
case "cell_info":
//TODO
break;
case "cell_location":
//TODO
break;
case "signal_strength":
//TODO
break;
}
}
catch (exc) {
console.log("Invalid JSON: " + exc);
}
},
function (error) {
console.log("ERROR! " + JSON.stringify(error));
},
{
"minTime": 500, // Min time interval between updates (ms)
"minDistance": 1, // Min distance between updates (meters)
"noWarn": true, // Native location provider warnings
"providers": "all", // Return GPS, NETWORK and CELL locations
"useCache": true, // Return GPS and NETWORK cached locations
"satelliteData": false, // Return of GPS satellite info
"buffer": false, // Buffer location data
"bufferSize": 0, // Max elements in buffer
"signalStrength": false // Return cell signal strength data
});
});
} else {
// **For IOS**
let options = {
frequency: 1000,
enableHighAccuracy: false
};
this.watch = this.geolocation.getCurrentPosition({ enableHighAccuracy: true }).then((resp) => {
console.log("current location at login" + JSON.stringify(resp.coords));
// Run update inside of Angular's zone
this.zone.run(() => {
this.currentLat = resp.coords.latitude;
this.currentLng = resp.coords.longitude;
});
}, Error => {
console.log(Error);
}).catch(Error => {
console.log(Error);
}) ;
}
});
}
}
I need to include a walki talkie in my app. I am always getting a registration failure -9 error code. I created 2 free Sip account (sip2sip.info, sip.linphone.org) and 1 commercial one (onsip.com). I added all those permission:
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.USE_SIP" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
and the following features:
<uses-feature android:name="android.hardware.sip.voip" android:required="true" />
<uses-feature android:name="android.hardware.wifi" android:required="true" />
<uses-feature android:name="android.hardware.microphone" android:required="true" />
I am calling the above fonction in the onCreate:
void log_and_register()
{
try
{
c.DEBUG().ftrace("VOIP Supported: " + SipManager.isVoipSupported(c.ma()));
c.DEBUG().ftrace("SIP API Supported: " + SipManager.isApiSupported(c.ma()));
mSipManager = SipManager.newInstance(c.ma());
SipProfile.Builder builder = new SipProfile.Builder(c.config().getSIP_UserName(), c.config().getSIP_Domain());
builder.setPassword(c.config().getSIP_Password());
//builder.setProtocol("UDP"); //"TCP");
//builder.setPort(5060); //5080 5070
builder.setAutoRegistration(true);
mSipProfile = builder.build();
}
catch (ParseException pe)
{
c.DEBUG().ftrace("incapable of parsing domain name, username or password!");
c.DEBUG().ASSERT(0 == 1);
}
try
{
Intent intent = new Intent();
intent.setAction("android.SipDemo.INCOMING_CALL");
PendingIntent pendingIntent = PendingIntent.getBroadcast(c.ma(), 0, intent, Intent.FILL_IN_DATA);
mSipManager.open(mSipProfile, pendingIntent, null);
}
catch (SipException se)
{
c.DEBUG().ftrace("WALKIE TALKIE NOT WORKING - Sip Exception!!");
c.DEBUG().ASSERT(0 == 1);
}
if (ContextCompat.checkSelfPermission(c.ma(), Manifest.permission.USE_SIP) == PackageManager.PERMISSION_GRANTED)
c.DEBUG().ftrace("GRANTED!!!");
else
ActivityCompat.requestPermissions(c.ma(), new String[]{Manifest.permission.USE_SIP}, 1);
try
{
if (mSipManager.isRegistered(mSipProfile.getUriString()))
{
c.DEBUG().ftrace("already registered !!" + mSipManager.isRegistered(mSipProfile.getUriString()));
return;
}
}
catch (Exception e)
{
c.DEBUG().ftrace("NO!!");
}
try
{
//mSipManager.register(mSipProfile, 30, new SipRegistrationListener(){
//mSipManager.register(mSipProfile, 30000, new SipRegistrationListener(){
c.DEBUG().ftrace("THIS IS THE TRACE BEFORE REGISTATION : " + mSipProfile.getUriString());
mSipManager.setRegistrationListener(mSipProfile.getUriString(), new SipRegistrationListener()
{
public void onRegistering(String localProfileUri)
{
c.DEBUG().ftrace("Registering with SIP Server...");
}
// next version has it!!
public void onRegistrationTimeout() {}
public void onRegistrationDone(String localProfileUri, long expiryTime)
{
c.DEBUG().ftrace("SIP Ready");
}
public void onRegistrationFailed(String localProfileUri, int errorCode, String errorMessage)
{
// -9 signifie qu'il y a un appel en cours
c.DEBUG().ftrace("CANNOT REGISTER domain=" + c.config().getSIP_Domain() + " / username=" + c.config().getSIP_UserName());
c.DEBUG().ftrace("SIP ERROR MSG : localProfileUri=" + localProfileUri + " errorCode=" + errCode(errorCode) + " errorMessage=" + errorMessage);
}
});
}
catch (Exception e)
{
c.DEBUG().ftrace("Cannot initialise wakie talkie!");
c.DEBUG().ASSERT(0 == 1);
}
// https:github.com/aosp-mirror/platform_development/commit/a025796211f15c2796f8ea3208c066801aa250b6
initiateCall();
}
public SipAudioCall call = null;
public void initiateCall() {
try {
SipAudioCall.Listener listener = new SipAudioCall.Listener() {
// Much of the client's interaction with the SIP Stack will
// happen via listeners. Even making an outgoing call, don't
// forget to set up a listener to set things up once the call is established.
#Override
public void onCallEstablished(SipAudioCall call) {
call.startAudio();
call.setSpeakerMode(true);
call.toggleMute();
}
#Override
public void onCallEnded(SipAudioCall call) {
}
};
c.DEBUG().ftrace("rafael - Format="+mSipProfile.getUriString());
//call = mSipManager.makeAudioCall(mSipProfile.getUriString(), sipAddress, listener, 30);
call = mSipManager.makeAudioCall(mSipProfile.getUriString(), "sip:rafael.hogue#sip2sip.info", listener, 30);
} catch (Exception e) {
Log.i("WalkieTalkieActivity/InitiateCall", "Error when trying to close manager.", e);
if (mSipProfile != null) {
try {
mSipManager.close(mSipProfile.getUriString());
} catch (Exception ee) {
Log.i("WalkieTalkieActivity/InitiateCall",
"Error when trying to close manager.", ee);
ee.printStackTrace();
}
}
if (call != null) {
call.close();
}
}
}
I compile for Nougat because I am using deprecated function. Then I modified my code to compile with Oreo.
I used Firewall Voip Checker to check my connection with my SIP server and the test 1 is successful but the second one seam to be in an infinite loop. One of the result of the test one is captured my attention but I don't know what it means:
Check NAT type
100% / Blocked or could not reach STUN server (but it's green so I guess it pass the test??). I had the flag :
android.useDeprecatedNdk=true
I change it to false...
and I always get the return code "registration faild"
I hadded this fonction to see what the -9 error code was:
// FOR MORE DETAILS SEE
// Sip Error while registration
// How to send instant message via SIP
//https://developer.android.com/reference/android/net/sip/SipErrorCode
private String errCode(int iErrorCode)
{
String sErr = "";
switch (iErrorCode)
{
case CLIENT_ERROR:
sErr = "client error!!";
break;
case CROSS_DOMAIN_AUTHENTICATION:
sErr = "cross domain authentification!!";
break;
case DATA_CONNECTION_LOST:
sErr = "data connection lost!!";
break;
case INVALID_CREDENTIALS:
sErr = "invalid credentials!!";
break;
case INVALID_REMOTE_URI:
sErr = "invalid remote uri!!";
break;
case IN_PROGRESS:
sErr = "In progress!!";
break;
case NO_ERROR:
sErr = "No error!!";
break;
case PEER_NOT_REACHABLE:
sErr = "peer not reachable!!";
break;
case SERVER_ERROR:
sErr = "server error!!";
break;
case SERVER_UNREACHABLE:
sErr = "server unreachable!!";
break;
case SOCKET_ERROR:
sErr = "socket error!!";
break;
case TIME_OUT:
sErr = "time out!!";
break;
case TRANSACTION_TERMINTED:
sErr = "No transaction terminated!!";
break;
default:
sErr = "No error detected!!";
break;
}
return (sErr);
}
The error message is "In progress..." witch means that he is busy already but I don't know what it means.
I when thru the error code on Wikipedia to have clues of the potential problem:
https://en.wikipedia.org/wiki/List_of_SIP_response_codes#4xx.E2.80.94Client_Failure_Responses
I tried to find a SDK of a higher lever to implement my walki talki and found.
I search for the app wireshark but I only found it for a laptop and not for my android smartphone.
It's important for me to implement the walki talkie because I am creating a app to increase the security of primary school daycare and we need to communicate with each other.
I tried to change the port and the communication protocol and I tried the AutoRegistration flag to true.
I tried to make a phone call after the registration failed in case the open statement did the registration assuming it could be trying to register a second time.
I have no more idea!!
I will implementing a WIFI Walki Talki without a sip account.
Reference: stackoverflow.com/questions/11176988/…
Then I will save, on startup, the port information, ip adresse, username of every smart phones (use by my collegue) into my firebase (online database) in order to establish communication without asking anything to the user to make it automatique.
I am realizing that if I have trouble connecting with sample code that is suppose to work this probably means that my clients will have the same kinds of problemes wish I want to avoid.
I don't need to communicate with people that are not on the same network but I think this method would also work over the internet even for cliente that are on an other router if they are all connected to the internet.
I'm building an android app, and I am going through the Facebook SDK examples, such as https://developers.facebook.com/docs/reference/dialogs/feed/
I can use the FeedDialogBuilder to create a story to share, but it only gives the options Share and Cancel, and doesn't give me the ability to set the audience (a particular friend, a list, etc.).
Is this possible using the FeedDialogBuilder, or do I need to request publish permissions and build my own facebook sharer?
Here's the code I'm using, after successfully logging in:
private void publishFeedDialog() {
Bundle params = new Bundle();
params.putString("name", "Facebook SDK for Android");
params.putString("caption", "Build great social apps and get more installs.");
params.putString("description", "The Facebook SDK for Android makes it easier and faster to develop Facebook integrated Android apps.");
params.putString("link", "https://developers.facebook.com/android");
params.putString("picture", "https://raw.github.com/fbsamples/ios-3.x-howtos/master/Images/iossdk_logo.png");
params.putString("display", "touch");
WebDialog feedDialog = (
new WebDialog.FeedDialogBuilder(getActivity(),
Session.getActiveSession(),
params))
.setOnCompleteListener(new OnCompleteListener() {
public void onComplete(Bundle values,
FacebookException error) {
if (error == null) {
// When the story is posted, echo the success
// and the post Id.
final String postId = values.getString("post_id");
if (postId != null) {
Toast.makeText(getActivity(),
"Posted story, id: "+postId,
Toast.LENGTH_SHORT).show();
} else {
// User clicked the Cancel button
Toast.makeText(getActivity().getApplicationContext(),
"Publish cancelled",
Toast.LENGTH_SHORT).show();
}
} else if (error instanceof FacebookOperationCanceledException) {
// User clicked the "x" button
Toast.makeText(getActivity().getApplicationContext(),
"Publish cancelled",
Toast.LENGTH_SHORT).show();
} else {
// Generic, ex: network error
Toast.makeText(getActivity().getApplicationContext(),
"Error posting story",
Toast.LENGTH_SHORT).show();
}
}
})
.build();
feedDialog.show();
}
See the setTo(String) method in FeedDialogBuilder.