Control DOM elements from android app - android

I'm trying to take control over the Play/Pause html DOM elements (in a browser open in a pc) from an android device.
In the html page (in Google Chrome browser) there's a <video> tag so I can control it like this:
//js code
document.querySelector("video").play();
document.querySelector("video").pause();
But I want that to run from an android device so I'm using GCM.
I read here and got some insight but I still have some questions.
First, since I'm writing in eclipse, and it sees no document variable, it produces an error. So how can eclipse recognize that element in the html page so I can compile and install the apk on the device?
Where do I specify the page url I want to communicate with? (send play/pause commands)
To run js inside java I'm using Rhino. I looked through the examples in the documentation but I'm still not sure if a #JSFunction annotation is enough to declare a js function.
Here's my code:
import com.alaa.chromote.util.SystemUiHider;
import com.google.android.gcm.GCMRegistrar;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.Toast;
import android.view.View.OnClickListener;
import org.mozilla.javascript.*;
import org.mozilla.javascript.annotations.*;
public class MainApplication extends Activity {
private final static String GCM_SENDER_ID = "484514826047";
private static final String LOG_TAG = "GetAClue::GCMIntentService";
private Button playButton;
private Button pauseButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_application);
playButton = (Button) findViewById(R.id.PlayButton);
pauseButton = (Button) findViewById(R.id.PauseButton);
playButton.setVisibility(View.INVISIBLE);
pauseButton.setVisibility(View.VISIBLE);
//connect to gcm
GCMRegistrar.checkDevice( this );
GCMRegistrar.checkManifest( this );
final String regId = GCMRegistrar.getRegistrationId( this );
if( regId.equals( "" ) ) {
GCMRegistrar.register( this, GCM_SENDER_ID );
}
else {
Log.v( LOG_TAG, "Already registered" );
}
Context.enter(); //start Rhino
setupListeners();
}
#JSFunction
public void play() { document.querySelector("video").play(); }
#JSFunction
public void pause() { document.querySelector("video").pause(); }
private void setupListeners()
{
playButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
play();
}
});
pauseButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
pause();
}
});
}
#Override
protected void onStop() {
Context.exit(); //stop Rhino
super.onStop();
}
}
How do I continue from here?

First, since I'm writing in eclipse, and it sees no document variable, it produces an error. So how can eclipse recognize that element in the html page so I can compile and install the apk on the device?
answ: On your android device you just pass a message to the chrome browser. A.k. an action variable that is set to play or stop. You chrome app will then pick up the message and act accordingly. Also you can send the url as an variable in the message if you want to be able to play different urls.
Where do I specify the page url I want to communicate with? (send play/pause commands)?
answ: Do you already created the chrome app you want and verified it works? It should check with a google cloud server for messages. That server keeps track of the url for you.
To run js inside java I'm using Rhino. I looked through the examples in the documentation but I'm still not sure if a #JSFunction annotation is enough to declare a js function.?
answ: It seems you are misunderstanding the part what the android app does (sending the play action) and what the chrome browser does (actually playing the movie)
I hope my answer has helped a little, feedback is appreciated :)

Related

NFC Android App acting differently on different phones

I have currently been testing some examples being found on the internet on sending NDEF messages through the NFC on my android phone.
I have three phones that I tested the phone with: Samsung Galaxy Nexus (Android 4.4.4), S3 (Android 4.4.2) and S4 (Android 4.4.4).
The app works perfect the way I wanted it to on the GN (it sends the message), however on the S3 and the S4 it sends the package name of the app instead of the message.
Can anybody help me with this? Does anyone know why or how to fix this? I am pretty new to Android dev and don't fully understand why it is doing this.
Code:
package tapit.cbstech.com.tap_it_3;
import android.app.Activity;
import android.nfc.NfcAdapter;
import android.os.Bundle;
import android.content.Intent;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter.CreateNdefMessageCallback;
import android.nfc.NfcEvent;
import android.os.Parcelable;
import android.widget.TextView;
import android.widget.Toast;
public class main extends Activity implements CreateNdefMessageCallback {
NfcAdapter mNfcAdapter;
TextView textView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView textView = (TextView) findViewById(R.id.textView);
// Check for available NFC Adapter
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
if (mNfcAdapter == null) {
Toast.makeText(this, "NFC is not available", Toast.LENGTH_LONG).show();
finish();
return;
}
// Register callback
mNfcAdapter.setNdefPushMessageCallback(this, this);
}
#Override
public NdefMessage createNdefMessage(NfcEvent event) {
String text = ("abcdefghi");
NdefMessage msg = new NdefMessage(
new NdefRecord[] { NdefRecord.createMime("text/plain", text.getBytes()),
/**
* The Android Application Record (AAR) is commented out. When a device
* receives a push with an AAR in it, the application specified in the AAR
* is guaranteed to run. The AAR overrides the tag dispatch system.
* You can add it back in to guarantee that this
* activity starts when receiving a beamed message. For now, this code
* uses the tag dispatch system.
*/
//NdefRecord.createApplicationRecord("hello test")
});
return msg;
}
#Override
public void onResume() {
super.onResume();
// Check to see that the Activity started due to an Android Beam
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {
processIntent(getIntent());
}
}
#Override
public void onNewIntent(Intent intent) {
// onResume gets called after this to handle the intent
setIntent(intent);
}
/**
* Parses the NDEF Message from the intent and prints to the TextView
*/
void processIntent(Intent intent) {
textView = (TextView) findViewById(R.id.textView);
Parcelable[] rawMsgs = intent.getParcelableArrayExtra(
NfcAdapter.EXTRA_NDEF_MESSAGES);
NdefMessage msg = (NdefMessage) rawMsgs[0];
textView.setText(new String(msg.getRecords()[0].getPayload()));
}
}
On the GNexus I get the "abcdefghi" but on the S3 and S4 I get "tapit.cbstech.com.tap_it_3"
Any help is appreciated! Thanks in advance!
Edit: Tested on a friends S3 and does the same (sending the package name) and tested on another friends nexus 5 (running Android L) and it worked sending the "abcdefghi" message.

Reading gmail inbox with android 4.2 up

I am trying to get the gmail inbox using javamail with this code:
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import com.sun.mail.imap.IMAPFolder;
import com.sun.mail.imap.IMAPStore;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import java.util.Properties;
public class HomeActivity extends Activity {
/**
* Called when the activity is first created.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button emailRead=(Button)findViewById(R.id.button);
emailRead.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Runnable r=new Runnable() {
#Override
public void run() {
Properties props = new Properties();
props.setProperty("mail.store.protocol", "imaps");
Session session = Session.getDefaultInstance(props, null);
IMAPStore imapStore = null;
try {
imapStore = (IMAPStore) session.getStore("imaps");
imapStore.connect("imap.gmail.com", "myemail#gmail.com", "mypassword");
final IMAPFolder folder = (IMAPFolder) imapStore.getFolder("Inbox");
folder.open(IMAPFolder.READ_WRITE);
Message m[]=folder.getMessages();
for(Message n:m){
System.out.println(n.getSubject());
}
} catch (MessagingException e) {
e.printStackTrace();
}
}
};
Thread t=new Thread(r);
t.start();
}
});
}
}
It works in emulator, but when run on a real device(with working internet connection) I constantly fail and get the exception:
com.sun.mail.util.MailConnectException: Couldn't connect to host, port: imap.gmail.com, 993; timeout -1;
nested exception is:
java.net.SocketTimeoutException: failed to connect to imap.gmail.com/2607:f8b0:400e:c02::6c (port 993) after 90000ms
Why am I receiving an MailConnectException, and how can I fix it?
EDIT:
Here are the links I have tried, but with the same result:
1)Reading Gmail mails using android SDK
2)Are there any good short code examples that simply read a new gmail message?
3)Reading all new messages from my gmail using javamail
Its just the subset of what I have tried before posting. I request someone to please share a live working code, which works on a real device here.
EDIT2:
I have tested this on three real devices. One was using wifi internet.Two others were using Gprs for net connectivity. So it appears that gmail setting for javamail have changed with android. The javamail code is working for me on desktop java.But seems something strange with android real devices.
U are not allowed to use networking in main UI thread from android 3.0 and up.
So setup aSyncTask to solve your problem

Simple gauge view like speedmeter in android?

I want to have a simple gauge view where i will define the start value and the end value and have a pointer to show given variable value.
So i can show a given value like speedmeter. For example if my the value of a textView is 1300, then next to the textview i want to have this custom meter view animation like this!
It is possible? Any existing example code?
Another one i found at Evelina Vrabie's blog, used it and worked perfect!
Look at Evelina Vrabie's GitHub.
It has a gauge library and some samples to interact with.
Big thanks to the owner Evelina Vrabie!
However it is not working on XHDPI/Few versions of android devices (above 4). Problem is the text in gauge view.
For anyone looking for simple gauge view I made a library that you can clone and use/modify for your needs.
CustomGauge
All other gauges you recommended have bugs and don't run fine on Kitkat and Lollipop. Also there is no Android Studio and gradle friendly library here.
Here's git repo for the more recent one updated for Lollipop you can use with Gradle:
https://github.com/Sulejman/GaugeView
After you include library in your project add gaugelibrary to xml layout of your activity:
<io.sule.gaugelibrary.GaugeView
android:id="#+id/gauge_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
gauge:showOuterShadow="false"
gauge:showOuterRim="false"
gauge:showInnerRim="false"
gauge:needleWidth="0.010"
gauge:needleHeight="0.40"
gauge:scaleStartValue="0"
gauge:scaleEndValue="100"
/>
This will show static gauge without needle. To instantiate needle with random animation you need to do that in activity class file. See how it's done here:
package io.sule.testapplication;
import android.app.Activity;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.view.Menu;
import android.view.MenuItem;
import java.util.Random;
import io.sule.gaugelibrary.GaugeView;
public class MainActivity extends Activity {
private GaugeView mGaugeView;
private final Random RAND = new Random();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mGaugeView = (GaugeView) findViewById(R.id.gauge_view);
mTimer.start();
}
private final CountDownTimer mTimer = new CountDownTimer(30000, 1000) {
#Override
public void onTick(final long millisUntilFinished) {
mGaugeView.setTargetValue(RAND.nextInt(101));
}
#Override
public void onFinish() {}
};
}
This will instantiate needle and make it animate moving to random values.
I made this one a while ago. Feel free to clone and modify. (It takes some ideas from the old Vintage Thermometer.)
github.com/Pygmalion69/Gauge
It can easily be added to your Gradle project:
repositories {
maven {
url 'https://www.jitpack.io'
}
}
dependencies {
compile 'com.github.Pygmalion69:Gauge:1.1'
}
The views are declared in XML:
<de.nitri.gauge.Gauge
android:id="#+id/gauge1"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_gravity="center"
android:layout_marginTop="10dp"
android:layout_weight="0.75"
gauge:labelTextSize="42"
gauge:maxValue="1000"
gauge:minValue="0"
gauge:totalNicks="120"
gauge:valuePerNick="10"
gauge:upperText="Qty"
gauge:lowerText="#string/per_minute" />
Here's an example of setting the values programmatically:
final Gauge gauge1 = (Gauge) findViewById(R.id.gauge1);
final Gauge gauge2 = (Gauge) findViewById(R.id.gauge2);
final Gauge gauge3 = (Gauge) findViewById(R.id.gauge3);
final Gauge gauge4 = (Gauge) findViewById(R.id.gauge4);
gauge1.moveToValue(800);
HandlerThread thread = new HandlerThread("GaugeDemoThread");
thread.start();
Handler handler = new Handler(thread.getLooper());
handler.postDelayed(new Runnable() {
#Override
public void run() {
gauge1.moveToValue(300);
}
}, 2800);
handler.postDelayed(new Runnable() {
#Override
public void run() {
gauge1.moveToValue(550);
}
}, 5600);
HandlerThread gauge3Thread = new HandlerThread("Gauge3DemoThread");
gauge3Thread.start();
Handler gauge3Handler = new Handler(gauge3Thread.getLooper());
gauge3Handler.post(new Runnable() {
#Override
public void run() {
for (float x = 0; x <= 6; x += .1) {
float value = (float) Math.atan(x) * 20;
gauge3.moveToValue(value);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
gauge4.setValue(333);
On this site you will find some free customizable gauges.
ScComponents
Very easy to install and well documented.
For example you can have for free something like this in 5 minutes following the instruction below.
Go on the above linked website. Click the GR004 and after the popup appear click on "Download for FREE".
The library will downloaded, unzip and follow the instruction to install the library (aar file) inside your Android project.
Write this code in your XML layout and your gauge will done:
<com.sccomponents.gauges.gr004.GR004
android:layout_width="match_parent"
android:layout_height="match_parent" />
You have many XML options to customize it:
sccAnimDuration
sccEnableTouch
sccInverted
sccFontName
sccLabelsSizeAdjust
sccMajorTicks
sccMaxValue
sccMinorTicks
sccMinValue
sccShowContour
sccShowLabels
sccText
sccValue
And the related function by coding.
I don't know whether the late answer is going to help or not. I also came to the same situation where i want to use a gauge to visualize data, since gauge is not given as widget in android, as a enthusiast i went for libraries like above which can be found through various links in the Internet, although it was quite helpful(thanks to the wonderful authors of it..) i find myself difficult to visualize the during certain situations, so another solution what i have done is for my app is i integreated the JavaScript gauges into my android application.
You can do that by the following steps
Create an asset folder in our project-look this link and you will see how to create an asset folder if someone don't knows about it.
Next one is you have design an html page on how your page sholud look like, for eg- header,no.of guages etc... and place it in the folder asset.
There are many sites which provide the guages like This is one site or you can browse other sites and take whatever you feel cool...!!
take it all including .js files and place it in the asset folder.
Android provides a class for handling webiview called "WebViewClient" you can browse more to know more about it in internet
This is sample code for viewing the webview content..
web = (WebView) findViewById(R.id.webview01);
progressBar = (ProgressBar) findViewById(R.id.progressBar1);
web.setWebViewClient(new myWebClient());
web.getSettings().setJavaScriptEnabled(true);
web.post(new Runnable() {
#Override
public void run() {
web.loadUrl("file:///android_asset/fonts/guage.html");
}
});
The above for loading the html & javscript.
public class myWebClient extends WebViewClient
{
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
// TODO Auto-generated method stub
super.onPageStarted(view, url, favicon);
}
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// TODO Auto-generated method stub
progressBar.setVisibility(View.VISIBLE);
view.loadUrl(url);
return true;
}
#Override
public void onPageFinished(WebView view, String url) {
// TODO Auto-generated method stub
super.onPageFinished(view, url);
progressBar.setVisibility(View.GONE);
}
}
This the webview class
You can also send data from activity to html page.. Refer This link
Kindly read through all, corrections are welcomed..!!
Use this : Sample Project
It can easily be added to your Gradle project:
repositories {
maven {
url 'https://www.jitpack.io'
}
}
dependencies {
implementation 'com.jignesh13.speedometer:speedometer:1.0.0'
}
The views are declared in XML:
<com.jignesh13.speedometer.SpeedoMeterView
android:id="#+id/speedometerview"
android:layout_width="250dp"
android:layout_height="250dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.453"
app:layout_constraintStart_toStartOf="parent"
app:backimage="#android:color/black"
app:needlecolor="#fff"
app:removeborder="false"
app:linecolor="#fff"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.079" />

Can not use MediaRecorder on Android Emulator. Is the storage location wrong?

I'm trying to record sound using Android Emulator. I know that this question is popular over the internet, I checked many posts, it seems that only one person succeded: Can the Android emulator record and play back audio using pc hardware?. (it think he used
File fTmFile; insteadof String fTmpFile;
which i also tried). And following Philip's advice and the official site tutorial http://developer.android.com/guide/topics/media/audio-capture.html and also other resources, I'm still not able to record. My application throws exception at line:
fMediaRecorder.prepare();
more exactley, this is what I first get:
W/System.err(1042): java.io.FileNotFoundException: /mnt/sdcard/audiorecordtest.3gp (Permission denied)
which makes me think is something wrong with the storage location, because even I added 'SD Card Support' property for the emulator with size 256 MiB, I'm not able to acces it, furthermore I can see in the emulator the message: "Your phone does not have a SD Card inserted" when I go to Music.
I added both audio record and external storage permissions, in AndroidManifest.xml and both audio (record+playback) hardware settings to the emulator 2.3.3 on Win 7. Is anything wrong within my app, the way I storage the file or something else? Please, if anybody has any idea feel free to share, it will be appreciated.
Here is the full source code:
import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
import android.app.Activity;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class RecordSoundActivity extends Activity {
private MediaRecorder fMediaRecorder = null;
private Button btnrecord;
private Button btnstop;
String fTmpFile;
public RecordSoundActivity() {
fTmpFile = Environment.getExternalStorageDirectory().getPath();
fTmpFile += "/audiorecordtest.3gp";
}
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btnrecord = (Button) findViewById(R.id.button1);
btnstop = (Button) findViewById(R.id.button2);
btnrecord.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
Toast.makeText(RecordSoundActivity.this, "Recording...", Toast.LENGTH_LONG).show();
Recording();
}
});
btnstop.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
fMediaRecorder.stop();
fMediaRecorder.release();
}
});
}
public void Recording() {
fMediaRecorder = new MediaRecorder();
fMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
fMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
fMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
fMediaRecorder.setAudioChannels(1);
fMediaRecorder.setAudioSamplingRate(8000);
fMediaRecorder.setOutputFile(fTmpFile);
try {
fMediaRecorder.prepare();
} catch (IOException e) {
// TODO: handle exception
e.printStackTrace();
}
try {
fMediaRecorder.start();
} catch (IllegalStateException e) {
// TODO: handle exception
e.printStackTrace();
}
//fMediaRecorder.stop();
//fMediaRecorder.release();
}
}
Try and see if it works for Android 4.0. I know I had some issues with the camera in the emulator, in lower version (Lower than 4.0) it just wouldn't recognize my laptop webcam. But when I tried it on 4.0, when the AVD was loading a popup message came and asked me if I want to connect the webcam to the AVD, and once I agreed it worked.
Another poster in SO asked this question too, about the camera, and changing the AVD version to 4.0 did help him.
Maybe its the same for audio recording too, as both are external hardware for the typical PC.

How can you set the http proxy programmatically?

I'm looking for a programmatic way to set-up http proxy settings for android handsets. I've tried using android.provider.Settings.System.putString() to set System.HTTP_PROXY, but my call fails (I'm using a 2.2 emulator image at the moment). My code looks like:
if (System.putString(getContentResolver(), System.HTTP_PROXY, "10.10.2.1:8080")) {
tv.append("put for HTTP_PROXY succeeded.\n");
}
else {
tv.append("put for HTTP_PROXY failed.\n");
}
I've also added to my android manifest:
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
..although it's not clear from the docs which permission, if any, is required.
I'm familiar with this SO thread, but the technique there requires manual adb commands, which require the SDK tools and (possibly) a rooted phone.
Is there a way to accomplish this? Ideally, I'd like away to set an http proxy that will be used for both data and wifi connections.
It's not possible to do this as a 3rd-party app. You get this message:
12-07 12:39:37.736: W/PackageManager(85): Not granting permission android.permission.WRITE_SECURE_SETTINGS to package com.mgranja.xxxxxxx (protectionLevel=3 flags=0xbe46)
Only apps that are signed with the same key as system apps can get this permission (i.e.: if you cook your own rom, you could add that funcionality)
More info about permission levels on this question, specially adamk's answer.
Why are these permissions being refused?
If you are limiting the use of proxies to your own application you can use the Proxy and ProxySelector API.
To set the proxy check Mike's answer;
Following is code snippet to retrieve proxy details
public static String getProxyDetails(Context context) {
String proxyAddress = new String();
try {
if (IsPreIcs()) {
proxyAddress = android.net.Proxy.getHost(context);
if (proxyAddress == null || proxyAddress.equals("")) {
return proxyAddress;
}
proxyAddress += ":" + android.net.Proxy.getPort(context);
} else {
proxyAddress = System.getProperty("http.proxyHost");
proxyAddress += ":" + System.getProperty("http.proxyPort");
}
} catch (Exception ex) {
//ignore
}
return proxyAddress;
}
It'll return empty if some exception or no proxy detected;
You can set the proxy for your application VM, but due to security reasons, third party apps may not have the functionality to set device proxy.
I found something here that looks like it might work
package com.BrowserSettings;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.provider.Settings;
public class BrowserSettingsUI extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final Button button = (Button) findViewById(R.id.Button01);
button.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
try {
Settings.System.putString(getContentResolver(),
Settings.System.HTTP_PROXY, "127.0.0.1:100");//enable proxy
}catch (Exception ex){
}
}
});
final Button button2 = (Button) findViewById(R.id.Button02);
button2.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
try {
Settings.System.putString(getContentResolver(),
Settings.System.HTTP_PROXY, "");//disable proxy
}catch (Exception ex){
}
}
});
}
}
You must add
<uses-permission android:name=”android.permission.WRITE_SETTINGS” />
to your manifest.
Did you try to call the com.android.settings.ProxySelector activity and let the user to enter the proxy? It's stored globally, but seems that it doesn't support the standard Proxy and ProxySelector API (for this problem there is already another question: How users/developers can set the Android's proxy configuration for versions 2.x?)

Categories

Resources