Showing an AlertDialog from a Webview outside of an Activity - android

I've been working on a feature similar to Facebook's chat heads - a feature which needs to be active for our users even if they leave our app to go check email, etc. It needs to be able to create AlertDialogs via javascript - from a place that isn't impacted when the user switches Activities inside our app. It's OK for the feature to close/hide when the user leaves the app to do something else - however it must still be present when they come back.
Other than using a Service I haven't been able to think of another way to let users interact with us while they're off doing other things. When I use a service to create the webview via WindowManager the webview's JsDialogHelper detects that the context is not an activity and prevents it from showing AlertDialogs.
Any ideas would be most helpful around making this work. We need to allow AlertDialogs to pop up and be interactive for this feature to be helpful. We need the webview to stick around between activity transitions.
Is it possible to extend JsDialogHelper so I can get it to work with my code? Is there a better way to have a facebook chat heads like feature using webviews in an android app that I haven't thought of yet? I'm open to complete rewrites if it gets the user experience I'm looking for.

You can display the Dialog from the service, by setting the window type as TYPE_SYSTEM_ALERT. Remember to communicate back the action taken by the user using the JsResult instance passed to onJsAlert.
// maintain reference to JsResult instance passed to onJsAlert, in order
// communicate back the action taken by the user.
private JsResult mResult;
webView.setWebChromeClient(new WebChromeClient() {
#Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
mResult = result;
AlertDialog dialog = new AlertDialog.Builder(MyService.this)
.setTitle("Custom Dialog")
.setMessage("This is our custom dialog, not the one served by JsDialogHelper")
.setOnCancelListener(new CancelListener())
.setNegativeButton("Cancel", new CancelListener())
.setPositiveButton("Ok", new PositiveListener())
.create();
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
dialog.show();
return true;
}
});
private class CancelListener implements DialogInterface.OnCancelListener,
DialogInterface.OnClickListener {
#Override
public void onCancel(DialogInterface dialogInterface) {
mResult.cancel();
}
#Override
public void onClick(DialogInterface dialogInterface, int i) {
mResult.cancel();
}
}
private class PositiveListener implements DialogInterface.OnClickListener {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
mResult.confirm();
}
}
Add the required permissions to the manifest file:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
Alternate solution:
If the web application can be built specific to android webview, then you can create Javascript interfaces which will allow Javascript code to directly invoke the Android code which in turn displays the dialog for you. This avoids the JsDialogHelper route.
Define a javascript interface:
public class WebAppInterface {
Context context;
WebAppInterface(Context c) {
context = c;
}
// Annotation required for api >= 17
#JavascriptInterface
public void showDialog() {
AlertDialog dialog = new AlertDialog.Builder(context)
.setTitle("Custom Dialog")
.setMessage("This is our custom dialog, not the one served by JsDialogHelper")
.create();
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
dialog.show();
}
}
Bind the interface between Javascript and Android code, using addJavascriptInterface.
webView.addJavascriptInterface(new WebAppInterface(this), "Android");
Use the interface in Javascript code.
<input type="button" value="Display dialog" onClick="displayDialog()" />
<script>
function displayDialog() {
//alert("Javascript Dialog");
Android.showDialog();
}
</script>
</input>

You can't display an AlertDialog outside of an Activity.
However, you could build a custom View which looks like the dialog you want to show, and display it in the window via WindowManager.
For example:
WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT
WindowManager.LayoutParams.TYPE_PHONE,
0,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.CENTER;
windowManager.addView(yourView, params);
The code above displays your custom view in the center of the screen, on top of everything else. You could inflate the view via LayoutInflater.
You also need to add the permission in the manifest in order to display the view.
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

I suppose you can create a JavaScript Interface for two way communication between your activity and WebView. I have not tried the solution myself, but have stumbled before on that. The SO Question posted here might help you on that.
I suppose your WebView will reside in an activity too, you can use the Activity's context to pop the AlertDialog. You just need a method in the activity which you'd like to call in the webview (I'd just pass the Activity object in the addJavascriptInterface method).
Another way would be to use a Service and initiate a new Activity which implements Theme.dialog in it to be used as AlertDialog.
Let me know if it doesn't solve your problem.

Related

show a license agreement in android application

We have to show a license agreement dialog when user use the application at the first time, now I have two questions about this:
1 Where to put this dialog?
Add another activity or put the dialog just at the MainActivity which is the launch acitivty?
2 How to close the app if user hit "Reject"
Once user hit the "Reject" button which means that he/she does not agree our license, then we have to exit the application completely. How to make it?
According to the answer of "Ahmad", I will decide to open a dialog or not at the beginning of the activity(the onCreate method):
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.map);
this.setupLicense();
this.setupViews();
this.initSomeJob();
}
private void setupLicense() {
SharedPreferences setting = getSharedPreferences(IConstant.Map_License, 0);
boolean mapLicenseAccept = setting.getBoolean(IConstant.Map_License, false);
if (!mapLicenseAccept) {
//user does not accept the license yet, we will open the dialog
showDialog(Dialog_Map_License);
}
}
#Override
protected Dialog onCreateDialog(int id) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
switch (id) {
case Dialog_Map_License:
builder.setIconAttribute(android.R.attr.alertDialogIcon)
.setTitle(R.string.map_license_title)
.setMessage(R.string.map_license_content)
.setPositiveButton(R.string.map_license_accept, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
//License accepted, persisted it.
SharedPreferences settings = getSharedPreferences(IConstant.Map_License, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putBoolean(IConstant.Map_License, true);
editor.commit();
}
})
.setNegativeButton(R.string.map_license_reject, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
//do nothing and exit
Process.killProcess(Process.myPid());
System.exit(0);
}
});
Dialog target = builder.create();
target.setCanceledOnTouchOutside(false);
return target;
}
return null;
}
But now I have meet two problem:
1 Event I choose the "Accept" button, once I open my app the second time, the dialog will show.
It seems that the following code does not work:
editor.putBoolean(IConstant.Map_License, true);
editor.commit();
2 When I show the dialog, the code:
this.setupViews();
this.initSomeJob();
will still run , they are not blocked which is out of expected, since nothing should be done before user hit the "Accept" button.
Any idea to fix it?
onCreateDialog has been deprecated. Use dialog fragment instead. The advantage will be that the code for displaying dialog will be moved from activity and you can then display dialog from any activity. Also move
SharedPreferences setting = getSharedPreferences(IConstant.Map_License, 0);
boolean mapLicenseAccept = setting.getBoolean(IConstant.Map_License, false);
to a utility method like isLicenceAccepted and similarly for storing the data
SharedPreferences settings = getSharedPreferences(IConstant.Map_License, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putBoolean(IConstant.Map_License, true);
editor.commit();
to method like acceptLicence in utility.
You can find how to make communication between dialog Fragment and your activity here. In your interface instead of onArticleSelected you will have to implement two methods onLicence accepted and onLicenceRejected. Implement the interface in you activity override these two methods and take appropriate action.
Where to put this dialog?
Right at the beginning, when the user opens the app for the first time. Keep track of that by saving it in your shared preferences, if this dialog has been already shown or not. You don't have to create a separate activity for this. You could, but most apps I've seen out there don't.
How to close the app if user hit "Reject"
Just finish the Activity and also save that in your shared preferences as well. So every time the user opens your app you check weather the boolean value for "hasUserAcceptedOurAgreement" is true or not and proceed depending on that.
I'm only answering from a technical standpoint on how this could be done reliably. I'm not a lawyer, but as far as I know, it's perfectly valid to just submit your license agreement to the play store, so it's available from the applications application page (Why else would there be this option?).

How exactly to act on a confirmation dialog?

New to Android... I understand Dialogs are asynchronous. But I really can't get my head around the flow for confirming an action. Can someone please explain the flow?
I want to save a file on the sdcard. The Activity prompts the used for the filename. Then it checks to see if the file exists. If it exists, it needs to prompt the user to confirm if they want to overwrite it. Then it proceeds to erase and write the file.
I know you can't hold execution waiting for the response. How then would this common flow work in Android?
Thanks
I am not 100% it is what you are looking for, but here is a link to the Android documentation explaining how we should display Confirmation and Acknowledgement popups using the "Android standard way":
http://developer.android.com/design/patterns/confirming-acknowledging.html
I do not know the exact flow, I suppose it would depend on how the application was written. I would check for the file if it existed call the dialog windows then if the Ok/Yes/Confirm is pressed overwrite the file.
Dialogs | Android Developers - Has an excellent code example
public class FireMissilesDialogFragment extends DialogFragment {
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Use the Builder class for convenient dialog construction
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage(R.string.dialog_fire_missiles)
.setPositiveButton(R.string.fire, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// FIRE ZE MISSILES! AKA Overwrite your file.
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// User cancelled the dialog AKA do nothing
}
});
// Create the AlertDialog object and return it
return builder.create();
}
}
I know it's slightly silly example but basically check for the file (if exist) > Call Dialog (if yes)> Overwrite.

How can we pass any value (selected one) from dialog to activity in android?

I need help to pass values from a custom dialog to an activity.
I cannot understand what should i use. I already used intent, but dialog doesn't support intent value passing .
So anyone can help me here, i am totally stucked.If you have any basic example for it, then that will be excellent.
Thank You.
Snippet from the Google Documentation:
// Alert Dialog code (mostly copied from the Android docs
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Pick a color");
builder.setItems(items, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
myFunction(item);
}
});
AlertDialog alert = builder.create();
// Now elsewhere in your Activity class, you would have this function
private void myFunction(int result){
// Now the data has been "returned" (as pointed out, that's not
// the right terminology)
}

Overriding backbutton android phonegap 1.8 jqmobile 1.1.0 jquery 1.7.1

I recently started developing a mobile app in Phonegap 1.8 + Jquerymobile 1.1.0 +jquery 1.7.1 for Android 2.3.3. My problem is:
I've tried overriding backbutton in Android in several ways, nothing works though. I've tried using
document.addEventListener("backbutton", handleBackButton, false);
function handleBackButton() {//do sth}
then I've just overrided it in Application.java code. And it works... almost.
My 1st page (index.html) is being just used to login after that there is main page (main.html) with links to other pages. I've overrided backbutton to goback on every other page than login and main. On those two pages it should exit the app after clicking "yes" in AlertDialog. Well, in MainPage it shows the AlertDialog and then goes straight back to login page without waiting even for my response. On login page it just shows the AlertDialog and waits for my reaction. Don't know why. Here is some of my code.
public void onBackPressed() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Are you sure you want to exit?")
.setCancelable(false)
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
SampleApplication.this.finish();
}
})
.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
AlertDialog alert = builder.create();
String testUrl = appView.getUrl();
if(testUrl.equals("file:///android_asset/www/index.html"))
{
alert.show();
}
if (testUrl.equals("file:///android_asset/www/main.html"))
{
alert.show();
}
if ((!testUrl.equals("file:///android_asset/www/index.html")) && (!testUrl.equals("file:///android_asset/www/main.html")))
{
this.appView.goBack();
}
}
What you could do is use the regular back button on all pages that you want the regular back button behaviour but create a separate button for the pages where you need a different behaviour and just make it look like the normal back button:
In your header bar, just add an anchor where you add a custom data-rel (and hook it up to whatever function you want) e.g.
<a data-rel="custombackbtn">Back</a>
Then add in that data-rel to wherever your regular back button is styled (your theme's css or regular css) so, wherever there's a mention of a[data-rel='back'] add data-rel='custombackbtn' e.g.
a[data-rel='back'], .ui-header a[data-rel='back'] {
*/Styling*/
}
is changed to
a[data-rel='back'], .ui-header a[data-rel='back'], a[data-rel='backbtn'], .ui-header a[data-rel='backbtn'] {
*/Styling*/
}

How to implement a confirmation (yes/no) DialogPreference?

How can I implement a Preference that displays a simple yes/no confirmation dialog?
For an example, see Browser->Setting->Clear Cache.
That is a simple alert dialog, Federico gave you a site where you can look things up.
Here is a short example of how an alert dialog can be built.
new AlertDialog.Builder(this)
.setTitle("Title")
.setMessage("Do you really want to whatever?")
.setIcon(android.R.drawable.ic_dialog_alert)
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
Toast.makeText(MainActivity.this, "Yaay", Toast.LENGTH_SHORT).show();
}})
.setNegativeButton(android.R.string.no, null).show();
Android comes with a built-in YesNoPreference class that does exactly what you want (a confirm dialog with yes and no options). See the official source code here.
Unfortunately, it is in the com.android.internal.preference package, which means it is a part of Android's private APIs and you cannot access it from your application (private API classes are subject to change without notice, hence the reason why Google does not let you access them).
Solution: just re-create the class in your application's package by copy/pasting the official source code from the link I provided. I've tried this, and it works fine (there's no reason why it shouldn't).
You can then add it to your preferences.xml like any other Preference. Example:
<com.example.myapp.YesNoPreference
android:dialogMessage="Are you sure you want to revert all settings to their default values?"
android:key="com.example.myapp.pref_reset_settings_key"
android:summary="Revert all settings to their default values."
android:title="Reset Settings" />
Which looks like this:
Use Intent Preference if you are using preference xml screen or you if you are using you custom screen then the code would be like below
intentClearCookies = getPreferenceManager().createPreferenceScreen(this);
Intent clearcookies = new Intent(PopupPostPref.this, ClearCookies.class);
intentClearCookies.setIntent(clearcookies);
intentClearCookies.setTitle(R.string.ClearCookies);
intentClearCookies.setEnabled(true);
launchPrefCat.addPreference(intentClearCookies);
And then Create Activity Class somewhat like below, As different people as different approach you can use any approach you like this is just an example.
public class ClearCookies extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
showDialog();
}
/**
* #throws NotFoundException
*/
private void showDialog() throws NotFoundException {
new AlertDialog.Builder(this)
.setTitle(getResources().getString(R.string.ClearCookies))
.setMessage(
getResources().getString(R.string.ClearCookieQuestion))
.setIcon(
getResources().getDrawable(
android.R.drawable.ic_dialog_alert))
.setPositiveButton(
getResources().getString(R.string.PostiveYesButton),
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog,
int which) {
//Do Something Here
}
})
.setNegativeButton(
getResources().getString(R.string.NegativeNoButton),
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog,
int which) {
//Do Something Here
}
}).show();
}}
As told before there are number of ways doing this. this is one of the way you can do your task, please accept the answer if you feel that you have got it what you wanted.

Categories

Resources