/*
AWSIotWebViewActivity.java
Copyright (c) 2016 NTT DOCOMO,INC.
Released under the MIT license
http://opensource.org/licenses/mit-license.php
*/
package org.deviceconnect.android.deviceplugin.awsiot.setting;
import org.deviceconnect.android.deviceplugin.awsiot.remote.BuildConfig;
import org.deviceconnect.android.deviceplugin.awsiot.remote.R;
import android.app.ActionBar;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Base64;
import android.view.KeyEvent;
import android.view.MenuItem;
import android.webkit.JavascriptInterface;
import android.webkit.JsPromptResult;
import android.webkit.JsResult;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.EditText;
import java.io.ByteArrayOutputStream;
public class AWSIotWebViewActivity extends Activity {
private static final boolean DEBUG = BuildConfig.DEBUG;
private static final String TAG = "Manager";
public static final String EXTRA_URL = "url";
public static final String EXTRA_TITLE = "title";
private static final String TYPE_IMAGE = "image/*";
private static final int INPUT_FILE_REQUEST_CODE = 1;
private static final int REQUEST_CODE_FROM_JS = 2;
private ValueCallback<Uri> mUploadMessage;
private ValueCallback<Uri[]> mFilePathCallback;
private WebView mWebView;
private boolean mPauseFlag;
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_web_view);
ActionBar actionBar = getActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
Intent intent = getIntent();
if (intent == null) {
finish();
return;
}
String url = intent.getStringExtra(EXTRA_URL);
if (url == null) {
finish();
return;
}
String title = intent.getStringExtra(EXTRA_TITLE);
if (title != null) {
setTitle(title);
}
mWebView = (WebView) findViewById(R.id.activity_web_view);
if (mWebView != null) {
mWebView.setWebViewClient(mWebViewClient);
mWebView.setWebChromeClient(mChromeClient);
mWebView.setVerticalScrollBarEnabled(false);
mWebView.setHorizontalScrollBarEnabled(false);
mWebView.addJavascriptInterface(new JavaScriptInterface(), "Android");
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setUseWideViewPort(true);
webSettings.setLoadWithOverviewMode(true);
webSettings.setDomStorageEnabled(true);
webSettings.setDatabaseEnabled(true);
webSettings.setAllowFileAccess(true);
webSettings.setAppCacheEnabled(false);
webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (DEBUG) {
if (0 != (getApplicationInfo().flags &= ApplicationInfo.FLAG_DEBUGGABLE)) {
WebView.setWebContentsDebuggingEnabled(true);
}
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
webSettings.setAllowFileAccessFromFileURLs(true);
webSettings.setAllowUniversalAccessFromFileURLs(true);
}
mWebView.loadUrl(url);
}
}
@Override
protected void onResume() {
super.onResume();
if (mWebView != null) {
mWebView.resumeTimers();
}
mPauseFlag = false;
}
@Override
protected void onPause() {
if (mWebView != null) {
mWebView.pauseTimers();
}
mPauseFlag = true;
super.onPause();
}
@Override
protected void onDestroy() {
if (mWebView != null) {
mWebView.destroy();
}
super.onDestroy();
}
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
if (android.R.id.home == item.getItemId()) {
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && mWebView.canGoBack()) {
mWebView.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
@Override
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
if (requestCode == INPUT_FILE_REQUEST_CODE) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (mFilePathCallback == null) {
super.onActivityResult(requestCode, resultCode, data);
return;
}
Uri[] results = null;
if (resultCode == RESULT_OK) {
String dataString = data.getDataString();
if (dataString != null) {
results = new Uri[] { Uri.parse(dataString) };
}
}
mFilePathCallback.onReceiveValue(results);
mFilePathCallback = null;
} else {
if (mUploadMessage == null) {
super.onActivityResult(requestCode, resultCode, data);
return;
}
Uri result = null;
if (resultCode == RESULT_OK) {
if (data != null) {
result = data.getData();
}
}
mUploadMessage.onReceiveValue(result);
mUploadMessage = null;
}
} else if(requestCode == REQUEST_CODE_FROM_JS) {
Uri selectedImage = data.getData();
String[] filePathColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver().query(selectedImage, filePathColumn, null, null, null);
if (cursor != null) {
cursor.moveToFirst();
cursor.close();
}
String imgPath = getPath(this, selectedImage);
BitmapFactory.Options options;
options = new BitmapFactory.Options();
options.inSampleSize = 3;
Bitmap bitmap = BitmapFactory.decodeFile(imgPath, options);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] b = stream.toByteArray();
String encodedString = Base64.encodeToString(b, Base64.DEFAULT);
mWebView.loadUrl("javascript:chooseImgResult(" + encodedString + ")");
} else {
super.onActivityResult(requestCode,resultCode, data);
}
}
private static String getPath(final Context context, final Uri uri) {
if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
private final WebViewClient mWebViewClient = new WebViewClient() {
private static final long STABLE_SCALE_CALCULATION_DURATION = 1000;
private long mStableScaleCalculationStart = System.currentTimeMillis();
private String mStableScale;
private long mRestoringScaleStart;
@Override
public void onScaleChanged(final WebView view, float oldScale, float newScale) {
final long now = System.currentTimeMillis();
if (mStableScale == null || (now - mStableScaleCalculationStart) < STABLE_SCALE_CALCULATION_DURATION) {
mStableScale = "" + newScale;
} else if (!mStableScale.equals("" + newScale)) {
boolean zooming = (now - mRestoringScaleStart) < STABLE_SCALE_CALCULATION_DURATION;
if (!zooming) {
mRestoringScaleStart = now;
view.zoomOut();
view.postDelayed(new Runnable() {
@Override
public void run() {
view.zoomOut();
}
}, STABLE_SCALE_CALCULATION_DURATION);
}
}
}
};
private final WebChromeClient mChromeClient = new WebChromeClient() {
@Override
public boolean onJsAlert(final WebView view, final String url, final String message, final JsResult result) {
if (mPauseFlag) {
return super.onJsAlert(view, url, message, result);
}
AlertDialog.Builder builder = new AlertDialog.Builder(AWSIotWebViewActivity.this);
builder.setTitle(R.string.app_name)
.setMessage(message)
.setCancelable(true)
.setPositiveButton(R.string.webview_js_alert_positive_btn, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
AlertDialog dialog = builder.create();
dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
result.confirm();
}
});
dialog.show();
return true;
}
@Override
public boolean onJsConfirm(final WebView view, final String url, final String message, final JsResult result) {
if (mPauseFlag) {
return super.onJsConfirm(view, url, message, result);
}
final boolean[] flag = new boolean[1];
AlertDialog.Builder builder = new AlertDialog.Builder(AWSIotWebViewActivity.this);
builder.setTitle(R.string.app_name)
.setMessage(message)
.setCancelable(true)
.setPositiveButton(R.string.webview_js_alert_positive_btn, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
flag[0] = true;
dialog.dismiss();
}
})
.setNegativeButton(R.string.webview_js_alert_negative_btn, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
flag[0] = false;
dialog.dismiss();
}
});
AlertDialog dialog = builder.create();
dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
if (flag[0]) {
result.confirm();
} else {
result.cancel();
}
}
});
dialog.show();
return true;
}
@Override
public boolean onJsPrompt(final WebView view, final String url, final String message, final String defaultValue, final JsPromptResult result) {
if (mPauseFlag) {
return super.onJsPrompt(view, url, message, defaultValue, result);
}
final EditText editText = new EditText(AWSIotWebViewActivity.this);
final boolean[] flag = new boolean[1];
AlertDialog.Builder builder = new AlertDialog.Builder(AWSIotWebViewActivity.this);
builder.setTitle(R.string.app_name)
.setView(editText)
.setCancelable(true)
.setPositiveButton(R.string.webview_js_alert_positive_btn, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int whichButton) {
flag[0] = true;
dialog.dismiss();
}
})
.setNegativeButton(R.string.webview_js_alert_negative_btn, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int whichButton) {
flag[0] = false;
dialog.dismiss();
}
});
AlertDialog dialog = builder.create();
dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
if (flag[0]) {
result.confirm(editText.getText().toString());
} else {
result.cancel();
}
}
});
dialog.show();
return true;
}
// For Android 5.0+
@Override
public boolean onShowFileChooser(final WebView webView, final ValueCallback<Uri[]> filePathCallback,
final FileChooserParams fileChooserParams) {
if (mFilePathCallback != null) {
mFilePathCallback.onReceiveValue(null);
}
mFilePathCallback = filePathCallback;
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType(TYPE_IMAGE);
startActivityForResult(intent, INPUT_FILE_REQUEST_CODE);
return true;
}
};
private class JavaScriptInterface {
private SharedPreferences mPref;
JavaScriptInterface() {
mPref = getSharedPreferences("__cookie.dat", Context.MODE_PRIVATE);
}
@JavascriptInterface
public void setCookie(final String name, final String value) {
SharedPreferences.Editor editor = mPref.edit();
editor.putString(name, value);
editor.apply();
}
@JavascriptInterface
public String getCookie(final String name) {
return mPref.getString(name, null);
}
@JavascriptInterface
public void deleteCookie(final String name) {
SharedPreferences.Editor editor = mPref.edit();
editor.remove(name);
editor.apply();
}
}
}