My android app used the old microsoft Translator very well but I am having
problems getting the app to work with the new Cognitive Services.
First I got a new azure translation account that has the following values
(these are not the real values)
Name: MYTranslateAcct
Resource group: translate
subscription ID: 981h5ce7-7ac7-4f6f-b4a5-ff04dc9e4266
key1 d122230418a8479ab5c06f2f1fca664c
key2 39c1f187o9814f4e983jba9eedd2e2c7
My first step is to try to get a token. Microsoft has docs on doing
this in JAVA but not in an Android environment. I dug around and have
put together some code but it is not working. One problem is that the
docs use terms that I don't have in my account such as "app-id" and
"key". I don't have those things - I just have the list of values
above.
Here is my code . . .
class translateMessage extends AsyncTask<Void, Void, String>
{
String retString;
String inString = null;
translateMessage(String inString) { this.inString = inString; }
#Override
protected String doInBackground(Void... arg0)
{
try
{
String key = "881b5ce7-9ac7-4f6f-b4a5-ff04dc9e3199";
String authenticationUrl = "https://api.cognitive.microsoft.com/sts/v1.0/issueToken";
HttpsURLConnection authConn = (HttpsURLConnection) new URL(authenticationUrl).openConnection();
authConn.setRequestMethod("POST");
authConn.setDoOutput(true);
authConn.setRequestProperty("Ocp-Apim-Subscription-Key", key);
IOUtils.write("", authConn.getOutputStream(), "UTF-8"); //following line of code gets the exception . . .
String token = IOUtils.toString(authConn.getInputStream(), "UTF-8"); //this blows
}
catch (Exception e)
{
String myString = e.getMessage();
String aString = "look at e";
}
return retString;
}
#Override
protected void onPostExecute(String result)
{
String debugStr = result;
translation.setText(result);
}
}
Following is the exception . . .
java.io.FileNotFoundException:https://api.cognitive.microsoft.com/sts/v1.0/issueToken
What am I doing wrong?
Is anyone aware of any working Android java code using the new services?
I posted this on Azure support and someone called me within an hour. I was passing the wrong key. When you get a translate cognitive account you get Key1 and Key2. Either of them will work. So the code is a useful example of working code that will get a token.
Related
I am trying getting data from an API using volley. I am trying to store it as a global variable, but it always returns null. Why?
Here is my sample code:
JsonObjectRequest jsonRequest = new JsonObjectRequest
(Request.Method.GET, url, null, response -> {
try {
if (response.getString("action").equals("success")) {
checkInTime = response.getString("checkin");
checkOutTime = response.getString("chekout");
System.out.println(response);
}
} catch (JSONException e) {
e.printStackTrace();
}
}, Throwable::printStackTrace);
Volley.newRequestQueue(MainActivity.this).add(jsonRequest);
What is the problem here?
here is my api json response
{"action":"success","checkin":"08:30:25","chekout":"blank"}
It does not working out of the request parenthesis
because this variable is temporary and it can be null if no data found.
So you have to write looks like
public static String checkInTime = "";
public static String checkOutTime = "";
After declaring global variable of String you can store data and can access from anywhere
checkInTime = response.getString("checkin");
checkOutTime = response.getString("chekout");
Its actually working for me
From the context you provided I guess you have a problem with some of these lines:
if (response.getString("action").equals("success")) {
checkInTime = response.getString("checkin");
checkOutTime = response.getString("chekout");
Reason 1 - you are not entering the if body
Reason 2 - you are not getting the response values properly
Try to debug the function
If I need to debug it I will:
Print the response before the IF statement
Print these values:
response.getString("action") checkInTime = response.getString("checkin"); checkOutTime = response.getString("chekout");
If it's being done from an Activity:
create a variable, e.g.:
public class MainActivity extends AppCompatActivity {
private String checkInTime;
Then in the code you posted above, add:
if (response.getString("action").equals("success")) {
this.checkInTime = response.getString("checkin");
Now try to access it from other places.
If it's not what you are looking for, please update the question with the relevant code regarding your global variable.
I see in the API that it's possible but I can't figure out how to use that sanitize() method. There's even a forum post where someone says to use it but they don't explain how. In essence I have no idea what CTX means in that method signature. If someone can provide sample code of how to get a list of items that were sanitized that would be appreciated.
You need to setup the HtmlChangeListener to catch all elements that are sanitized. The code then looks something like:
List<String> results = new ArrayList<String>();
HtmlChangeListener<List<String>> htmlChangeListener = new HtmlChangeListener<>()
{
#Override
public void discardedTag(List<String> context, String elementName)
{
context.add(elementName);
}
#Override
public void discardedAttributes(List<String> context, String tagName, String... attributeNames)
{
context.add(tagName);
}
};
String sanitizedHtml = POLICY_DEFINITION.sanitize(rawHtml, htmlChangeListener, results);
System.out.println("Sanitized elements include: " + String.join(",", results));
My overall goal is to be able to automatically download a daily report using the bing ads API. To do this, I need to authenticate with OAuth (the old PasswordAuthentication method doesn't work because I have a new microsoft account). I have been through the "Authorization Code Grant Flow" manually and authorised myself successfully. The problem is:
the token is only valid for 1 hour
when the token expires, the process requires the user to manually login using a web browser again and re-allow the app access
Here's an example desktop app using OAuth
Does somebody know either
a more fitting way of authenticating?
or a way of bypassing the user interaction?
SOLUTION:
As mentioned by #eric urban it is only necessary to authorize manually, once. after that, the refresh token will do. (Not really obvious just looking at the example desktop app!)
I wrote a class to deal with all the OAuth stuff and persist the refresh token to a file
public class OAuthRefreshToken {
private static String refreshTokenFileName = "./bingAdsRefreshToken.txt";
private static String ClientId = "XXXXX";
private final OAuthDesktopMobileAuthCodeGrant oAuthDesktopMobileAuthCodeGrant = new OAuthDesktopMobileAuthCodeGrant(ClientId);
private String refreshToken;
public OAuthRefreshToken() {
oAuthDesktopMobileAuthCodeGrant.setNewTokensListener(new NewOAuthTokensReceivedListener() {
#Override
public void onNewOAuthTokensReceived(OAuthTokens newTokens) {
String refreshTime = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
.format(new java.util.Date());
refreshToken = newTokens.getRefreshToken();
System.out.printf("Token refresh time: %s\n", refreshTime);
writeRefreshTokenToFile();
}
});
getRefreshTokenFromFile();
refreshAccessToken();
}
public OAuthRefreshToken(String refreshToken) {
this.refreshToken = refreshToken;
writeRefreshTokenToFile();
}
public OAuthDesktopMobileAuthCodeGrant getoAuthDesktopMobileAuthCodeGrant() {
return oAuthDesktopMobileAuthCodeGrant;
}
private void refreshAccessToken(){
oAuthDesktopMobileAuthCodeGrant.requestAccessAndRefreshTokens(refreshToken);
}
private void getRefreshTokenFromFile(){
try {
refreshToken = readFile(refreshTokenFileName, Charset.defaultCharset());
} catch (IOException e) {
e.printStackTrace();
}
}
private static String readFile(String path, Charset encoding)
throws IOException
{
byte[] encoded = Files.readAllBytes(Paths.get(path));
return new String(encoded, encoding);
}
private void writeRefreshTokenToFile(){
File refreshTokenFile = new File(refreshTokenFileName);
try {
FileWriter f2 = new FileWriter(refreshTokenFile);
f2.write(refreshToken);
f2.close();
} catch (IOException e) {
e.printStackTrace();
return;
}
System.out.printf("New refresh token: %s\n", refreshToken);
System.out.printf("Stored Safely in: %s\n", refreshTokenFileName);
}
}
Use it in your app like:
final OAuthRefreshToken oAuthRefreshToken = new OAuthRefreshToken();
final OAuthDesktopMobileAuthCodeGrant oAuthDesktopMobileAuthCodeGrant = oAuthRefreshToken.getoAuthDesktopMobileAuthCodeGrant();
You are correct that user consent is required up front (once). Thereafter you can use the refresh token to request additional access tokens without user interaction. For details about Authorization Code grant flow using the Bing Ads Java SDK please see Getting Started Using Java with Bing Ads Services. Does this help?
The refresh token should not expire that quickly, they are usually permanent or last a very long time. These can however be revoked, or invalidated if you request too many of them. i believe when you have requested more than 25 different refresh tokens, they older ones start to become invalid.
I have the following method in my Android app which I use for user login/registration.
public void registerUser(final String username, final String email, final String password) {
pDialog.setMessage("Signing Up...");
pDialog.show();
request = new StringRequest(Method.POST, SL_URL, new Response.Listener<String>() {
#Override
public void onResponse(String s) {
pDialog.dismiss();
String[] split = s.split("Config.php");
String after = split[1];
try {
JSONObject jsonObject = new JSONObject(after);
boolean error = jsonObject.getBoolean("error");
if (error) {
String errorMsg = jsonObject.getString("error_msg");
Toast.makeText(getApplicationContext(),
errorMsg, Toast.LENGTH_LONG).show();
} else {
session.setLogin(true, username, email);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}) {
#Override
protected Map<String, String> getParams() throws AuthFailureError {
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("tag", "login");
hashMap.put("username", name);
hashMap.put("password", password);
return hashMap;
}
};
queue.add(request);
}
Now I am writing my app for iOS and trying to replicate this in Swift. So far I have the following code:
let username = usernameTxt.text
let password = passwordTxt.text
let urlPath: String = "***"
let url: NSURL = NSURL(string: urlPath)!
let request1: NSMutableURLRequest = NSMutableURLRequest(URL: url)
request1.HTTPMethod = "POST"
let stringPost="tag=login&username=" + username! + "&password=" + password! // Key and Value
NSLog(stringPost)
let data = stringPost.dataUsingEncoding(NSUTF8StringEncoding)
request1.timeoutInterval = 60
request1.HTTPBody=data
request1.HTTPShouldHandleCookies=false
let queue:NSOperationQueue = NSOperationQueue()
NSURLConnection.sendAsynchronousRequest(request1, queue: queue, completionHandler:{ (response: NSURLResponse?, data: NSData?, error: NSError?) -> Void in
do {
var jsonResult: NSDictionary = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
} catch _ {}
})
Now as someone new to iOS development and Swift in general, I have the following questions:
What is the best way to replicate the progressDialog I use in Java in Swift, it must be visible until the request is complete and then it should be dismissed. I'm guessing this should be placed in the completionHandler, however I'm not sure which UI element to use for the progress Dialog.
How do I obtain my response as a String and replicate the behaviour of the split function, and then convert the result of this into a jsonObject like I do in my Java code.
What is the best way to replicate the Toast used to show the error message. I don't think using a dialog which must be closed with a button would be optimal here.
Thank you.
I am also developing Applications for Android and IOS. Here i Answered your three Problems which is faced by me also as a beginner. I hope this would help you.
1) Use MBProgressHUD Link to replicate the progressDialog in Swift .There are two method to show and dismiss the progressDialog:
Use showLoadingHUD() before making HTTP request
private func showLoadingHUD() {
let hud = MBProgressHUD.showHUDAddedTo(self.view, animated: true)
hud.labelText = "Loading..."
}
And hideLoadingHUD() after receiving the response from server
private func hideLoadingHUD() {
MBProgressHUD.hideAllHUDsForView(self.view, animated: true)
}
2) you can use Alamofire Link which can handle Network stuff And you can easily obtain response in String.
Example:
self.showLoadingHUD()
Alamofire.request(.GET, data, parameters: nil)
.response { (request, response, data, error) in
print(data) // if you want to check data in debug window.
let Result = NSString(data: data!, encoding: NSUTF8StringEncoding)
Result!.stringByReplacingOccurrencesOfString("\"", withString: "")
if(newResult == "1"){
self.navigationController!.popViewControllerAnimated(true)
JLToast.makeText("Success").show()
}
else if (newResult == "0"){
JLToast.makeText("Failed").show()
}
self.hideLoadingHUD()
3) mankee Toas are used for a purpose of displaying information for short period of time and disappear themselves. Here we can use Android like Toast which is JLToast. Available on github .
JLToast.makeText("Success").show()
I have a simple web service in c#.
Here is the C# code :
IService1.cs
[ServiceContract(ConfigurationName = "IService")]
public interface IService1
{
[OperationContract]
[WebGet]
string TestAndroid();
}
Service1.svc.cs
public class Service1 : IService1
{
public string TestAndroid()
{
return "Test done !";
}
}
Here is the Android code :
protected Boolean doInBackground(String... urls) {
try {
URL url = new URL("http://10.0.2.2:49363/Service1.svc/TestAndroid");
InputStream in = new BufferedInputStream(httpURLConnection.getInputStream());
BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
String line = reader.readLine();
reader.close();
} catch(Exception e){
return false;
}
return null;
}
When I want to read the InputStream, I have an error.
It's
java.io.FileNotFoundException:
http://10.0.2.2:49363/Service1.svc/TestAndroid
I don't know where is the problem, because when I go in browser I have
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">Test done !</string>
Can someone help me ?
I hope your service is working and you had tested it on your computer by invoking url http://10.0.2.2:49363/Service1.svc/TestAndroid
Am I right?
Then simple explanation for your issue would be that your Android doesn't know about ip address 10.0.2.2.
Can you validate that is accessible? Just try to open the same url in browser on your Android device.
Simple solution to see this IP address - your phone should be on the same WiFi as your computer.
Update:
Goal is to see computer with service running WCF host. Question is - can Android device see WCF host?
The opposite direction is irrelevant but it's good to know that
Android emulator cannot be seen from the computer. Here is good explanation