I am new to Android and Java. I have constructed an app using HTML/Javascript that is working great.
I now need to create an activity that launches the email client, fills in subject and body, and (the tough part) adds a file attachment. I have not been able to do this from within JavaScript, mailto: will not attach the file.
So I need to accomplish this through Java and execute it from JavaScript. I think this can be done by using addJavaScriptInterface but I cannot find any detailed documentation or examples to go off of.
How could I do this?
Here is what I have so far after reading the documentation:
2nd update to code:
MainActivity.java
public class MainActivity extends DroidGap {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.setIntegerProperty( "splashscreen", R.drawable.splash );
super.loadUrl("file:///android_asset/www/index.html", 1000);
WebView mWebView;
mWebView = (WebView)findViewById(R.id.webview);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.addJavascriptInterface(new JavaScriptInterface(), "Android");
}
}
JavaScriptInterface.java
public class JavaScriptInterface {
public void doEmail(){
Intent sendIntent = new Intent(Intent.ACTION_SEND);
sendIntent.setType("text/html");
sendIntent.putExtra(android.content.Intent.EXTRA_TEXT,"test text");
sendIntent.putExtra(Intent.EXTRA_SUBJECT,"test subject");
sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
sendIntent.putExtra(Intent.EXTRA_STREAM,Uri.parse("file://test co.html"));
startActivity(Intent.createChooser(sendIntent, "Send email..."));
}
}
Then I would reference the intent through JavaScript by using Android.doEmail().
With the above code I am getting 2 errors in Eclipse
1. The method startActivity(Intent) is undefined for the type - JavaScriptInterface
2. webview cannot be resolved or is not a field - MainActivity
What am I doing wrong?
This documentation tells you exactly how to do it.
It looks like there are three main steps:
Create your 'interface' class in Android
Add an instance of this 'interface' to the WebView you are using.
Call the interface from your JavaScript.
public class MainActivity extends DroidGap {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.setIntegerProperty( "splashscreen", R.drawable.splash );
JavaScriptInterface jsi = new JavaScriptInterface(this, appView);
appView.addJavascriptInterface(jsi, "Android");
super.loadUrl("file:///android_asset/www/index.html", 1000);
}
}
and
public class JavaScriptInterface {
private WebView mAppView;
private DroidGap mGap
public JavaScriptInterface (DroidGap gap, WebView view)
{
mAppView = view;
mGap = gap;
}
public void doEmail(){
Intent sendIntent = new Intent(Intent.ACTION_SEND);
sendIntent.setType("text/html");
sendIntent.putExtra(android.content.Intent.EXTRA_TEXT,"test text");
sendIntent.putExtra(Intent.EXTRA_SUBJECT,"test subject");
sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
sendIntent.putExtra(Intent.EXTRA_STREAM,Uri.parse("file://test co.html"));
startActivity(Intent.createChooser(sendIntent, "Send email..."));
}
}
Using addJavaScriptInterface will extend the DOM inside the embedded browser, and allow JS to access a Java object, which is exactly what you want.
There are too many steps to outline here, that have already been documented. This link has a good overview.
I used WebIntents from Boris Smus (http://smus.com/android-phonegap-plugins) and it works like a charm. You can also peruse his code a little to understand better the approach he took with plugins.
NOTE: you do need to update the code provided as is a little (see comments) and the plugin architecture has changed a little.
Related
I am building an android application that shows 360-degree images in VRview. for this I am using unity as a library to show the 360 images (as a skybox). But I couldn't figure out a way to change the 360 images (skybox) based on the user input.
Here is what I did.
first I created a unity project imported a 360 image and made it skybox, wrote scripts, and prepared the VRview then exported it for android. Then I created an android studio project, imported and called the unity library from the android java class, and tested it on an actual device, and it worked fine. But it only works for only one 360-degree image.
To support multiple images, I created a function inside the C# script to change the image (skybox) of the scene and tried to call it from the android by passing a string that is used to identify which skybox to set.
This is explained in a question:
How to call Unity C# method from Android java project by UnitySendMessage method?
To call the C# function, It suggests using
UnityPlayer. UnitySendMessage("Gameobject Name","Method","Message")
But it didn't work for me.
Here is the java class that is used to call the Unity library
public class MainActivity2 extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
}
public void toVr(View view) {
Intent i = new Intent(MainActivity2.this, UnityPlayerActivity.class);
i.putExtra("data", "skybox1");
startActivity(i);
}
}
Here is the UnityPlayerActivity onCreate method from which I tried to call the Unity C# method
#Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
String cmdLine = updateUnityCommandLineArguments(getIntent().getStringExtra("unity"));
getIntent().putExtra("unity", cmdLine);
mUnityPlayer = new UnityPlayer(this, this);
setContentView(mUnityPlayer);
mUnityPlayer.requestFocus();
Intent i = getIntent();
String ss = i.getStringExtra("data");
if (ss.equals("skybox1")) {
UnityPlayer.UnitySendMessage("Script", "initiateBackground", "skybox1");
} else {
Toast.makeText(this, "no display", Toast.LENGTH_SHORT).show();
}
}
Here is Unity C# code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SkyboxScript : MonoBehaviour
{
public Material skyOne;
public Material skytwo;
void Start(){
}
public void initiateBackground(string skybox){
if(skybox.Equals("skybox1")){
RenderSettings.skybox = skytwo;
}
}
}
I need help to figure out how to call initiateBackground(string) method from the android java class. any type of help is appreciated.
I am a newbie to android development, trying to get buttons working. every time i use this code below, the error message "unfortunately the app has stopped". but when i remove the code the app runs but obviously the buttons do nothing. here is the code ive tried
public class MyActivity extends Activity {
/**
* Called when the activity is first created.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button button1 = (Button) findViewById(R.id.ExerciseButton);
button1.setOnClickListener (new View.OnClickListener(){
public void onClick(View v) {
setContentView(R.layout.exercises);
}
});
}
}
anybody able to help me out there? thanks
Don't try to load another View in the current activity. Navigate to a new ExercisesActivity.
Use:
public void onClick(View v) {
Intent intent = new Intent(ExercisesActivity.this, WcActivity.class);
startActivity(intent);
}
You can't call setContentView anymore after the view has loaded (which it obviously has to receive button clicks). Use a different approach, like showing and hiding views or using a ViewFlipper (see Calling setContentView() multiple times), using fragments (see Fragments) or starting a new activity.
Well, from your code, I see a couple of things:
I am usually familiar to using the onClickListener of the Button class if I want to use it for a button. Makes sense, doesn't it?
buttonOne.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
//Do stuff here
}
Second thing:
Start a new Activity (if that is what you want) by using an Intent:
Intent myIntent = new Intent(this, exercises.class);
startActivity(myIntent);
You CAN absolutaly call setContentView on any event, even after the view has loaded
I tried your code in a demo project and it is working fine. So, i think the error will be some where in your layout.(Let me know more if you need more help on this)
I am learning Android. I learned to use my app to start another app I wrote. Using this code below:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button appOpener = (Button) findViewById(R.id.button1);
appOpener.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
Intent i = new Intent(Intent.ACTION_MAIN);
PackageManager firstApp = getPackageManager();
i = firstApp.getLaunchIntentForPackage("com.assignment.projecttomiko");
}
});
}
It's pretty straight-forward and I am happy wit it. But now I want to start apps already on the Android platform itself, like browser, calender, calculator, etc. From the above, I see I just have to put in the package name of my other apps. I am assuming I can do the same thing to say start a calculator. Or maybe not. What is the best way to do this? If I can use package names, then what are the package names of these in-built apps. If there's a better way I would like someone to help me out.
I read this: Opening System Application Using Intent and realised there's an introduction of an extra LaunchComponent I don't know what that is but the main thing is I see on that thread that they are also putting in some package names to call system apps. What'll be your best way to get this done? :)
EDIT:
I searched for hours and tried this code but doesn't work :(
// activity name and package for stock calculator
private static final String CALCULATOR_PACKAGE_NAME = "com.android.calculator2";
private static final String CALCULATOR_CLASS_NAME = "com.android.calculator2.Calculator";
public void launchCalculator() {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setComponent(new ComponentName(CALCULATOR_PACKAGE_NAME,
CALCULATOR_CLASS_NAME));
try {
this.startActivity(intent);
} catch (ActivityNotFoundException noSuchActivity) {
// handle exception where calculator intent filter is not registered
}
}
I'm trying to call JS functions from Android native code, but they don't seem to be working. I've tried many solutions but to no solution. Here is my code:
public class MainActivity extends Activity {
private WebView webView;
#SuppressLint("SetJavaScriptEnabled")
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webView = (WebView) findViewById(R.id.webView1);
webView.setWebViewClient(new MyCustomWebViewClient());
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
webView.getSettings().setUseWideViewPort(true);
webView.getSettings().setLoadWithOverviewMode(true);
webView.loadUrl("http://google.com");
}
private class MyCustomWebViewClient extends WebViewClient {
#Override
public void onPageFinished(WebView view, String url) {
webView.loadUrl("javascript:alert('shadow');");
Toast.makeText(getApplicationContext(), "DONE", Toast.LENGTH_LONG).show();
}
}
}
Please help.
Thanks
You can't do alert() with Android's WebView. If you want to show alert dialogs, you need to handle it in your Activity code or use a WebChromeClient. Per the docs:
Creating and setting a WebChromeClient subclass. This class is called
when something that might impact a browser UI happens, for instance,
progress updates and JavaScript alerts are sent here (see Debugging
Tasks).
See: https://developer.android.com/reference/android/webkit/WebView.html
With a WebView you can still write a JavaScript function that sets the value of a textbox to some string. If you need specific code to help you with this, let me know. If you've gotten this far though, you probably can handle it on your own is my guess.
Edit 1
First create a method in JavaScript called sendValueToAndroid()
myWebView.loadUrl("javascript:sendValueToAndroid()");
In the JavaScript method, call an exposed method in your Android code.
function sendValueToAndroid()
{
val divValue = ...
Android.sendValueToAndroid(divValue);
}
Expose a method in the Android app in any object of your choosing.
#JavascriptInterface
public String sendValueToAndroid(String val)
{
//do something in your app
}
Basically, what you're doing is telling the WebView to invoke a JavaScript method which invokes a callback method in your own app.
I am a beginner in developing and I know the question may sounds very basic but, let me cut to the chase: here is my class
public class MainActivity extends Activity {
private ListView lvPhone;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lvPhone = (ListView)findViewById(R.id.listPhone);
List<PhoneBook> listPhoneBook = new ArrayList<PhoneBook>();
listPhoneBook.add(new PhoneBook(
BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher),
"blah_blah", "384765345667", "something#someprovider.com"));
listPhoneBook.add(new PhoneBook(
BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher),
"blah_blah", "34856834796", "something#someprovider.com"));
listPhoneBook.add(new PhoneBook(
BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher),
"blah_name", "868734633", "something#someprovider.com"));
PhoneBookAdapter adapter = new PhoneBookAdapter(this, listPhoneBook);
lvPhone.setAdapter(adapter);
}
}
and here I'd like it to be "attached" so then when the button is clicked the phone book comes up.
public void addListenerOnButton(){
imageButton = (ImageButton) findViewById(R.id.pb_button);
imageButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
Toast.makeText(MyAndroidAppActivity.this,//phone_book goes here
"ImageButton is clicked!", Toast.LENGTH_SHORT).show();//no toaster instead
}
});
}
Would any of you please help? This is going to be really helpful for me. And please if you do answer, try to explain as you're explaining to a "Java_moron" :) (as through as possible please)
[Now I did try the chat room, no reputation point so that didn't happen and I tried to google as much as possible couldn't find anything helpful; maybe there was answer but my lack of knowledge failed me.]
Thank you,
[EDIT: Or instead of using the phone book class, how can I call contacts from phone's native contact list? Anything would be helpful really.]
The best option to start would be to activate a native activity that will bring up phone book contacts and show them to the user as a list. Selected contacts is then passed to starting activity.
Explanation:
You can learn how to start an activity and receive result from the following link:
http://developer.android.com/training/basics/intents/result.html
Basically the main code do that is as follows:
static final int PICK_CONTACT_REQUEST = 1; // The request code
...
private void pickContact() {
Intent pickContactIntent = new Intent(Intent.ACTION_PICK, new Uri("content://contacts"));
pickContactIntent.setType(Phone.CONTENT_TYPE); // Show user only contacts w/ phone numbers
startActivityForResult(pickContactIntent, PICK_CONTACT_REQUEST);
}
Note that the user will be calling the startActivityForResult method this will start a new activity and once that activity is finished the System will call onActivityResult() method of the original Activity and here you will receive results to which contacts has been selected.