Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
Browse files
Update Android code to work with latest 4.0.x
  • Loading branch information
agrieve committed May 13, 2015
1 parent 101b9ff commit 675a3d31df9af18ef396516d3826eb9f9d31d0a4
Showing 5 changed files with 112 additions and 81 deletions.
@@ -18,6 +18,8 @@ Licensed to the Apache Software Foundation (ASF) under one
*/
package org.apache.appharness;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
@@ -27,39 +29,48 @@ Licensed to the Apache Software Foundation (ASF) under one
import org.apache.cordova.CordovaActivity;
import org.apache.cordova.CordovaArgs;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.LinearLayoutSoftKeyboardDetect;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.CordovaWebViewEngine;
import org.apache.cordova.CordovaWebViewImpl;
import org.apache.cordova.PluginEntry;
import org.apache.cordova.PluginResult;
import org.apache.cordova.whitelist.WhitelistPlugin;
import org.json.JSONArray;
import org.json.JSONException;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;

import android.annotation.TargetApi;
import android.content.res.XmlResourceParser;
import android.net.Uri;
import android.os.Build;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewPropertyAnimator;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.LinearLayout;

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class AppHarnessUI extends CordovaPlugin {
private static final String LOG_TAG = "AppHarnessUI";
ViewGroup contentView;
View origMainView;
CustomCordovaWebView slaveWebView;
CordovaWebView slaveWebView;
CustomCordovaWebView slaveWebViewEngine;
boolean slaveVisible;
CallbackContext eventsCallback;
LinearLayoutSoftKeyboardDetect layoutView;

@Override
public void pluginInitialize() {
contentView = (ViewGroup)cordova.getActivity().findViewById(android.R.id.content);
}

public boolean isSlaveVisible() {
return slaveVisible;
}

public boolean isSlaveCreated() {
return slaveWebView != null && slaveWebView.getView().getParent() != null && ((ViewGroup)slaveWebView.getView().getParent()).getParent() != null;
return slaveWebView != null && slaveWebView.getView().getParent() != null;
}

@Override
@@ -126,10 +137,10 @@ public void sendEvent(String eventName) {
}

private void evalJs(String code, CallbackContext callbackContext) {
if (slaveWebView == null) {
if (slaveWebViewEngine == null) {
Log.w(LOG_TAG, "Not evaluating JS since no app is active");
} else {
slaveWebView.evaluateJavascript(code);
slaveWebViewEngine.evaluateJavascript(code);
}
callbackContext.success();
}
@@ -140,24 +151,24 @@ private void create(String url, Set<String> pluginIdWhitelist, CallbackContext c
if (slaveWebView != null) {
Log.w(LOG_TAG, "create: already exists");
} else {
slaveWebView = new CustomAndroidWebView(this, activity);
slaveWebViewEngine = new CustomAndroidWebView(this, activity);
slaveWebView = new CordovaWebViewImpl(webView.getContext(), (CordovaWebViewEngine)slaveWebViewEngine);
// A consistent view ID is needed for plugins that utilize the background-activity plugin.
slaveWebView.getView().setId(200);
// We'll set the plugin entries in initWebView.
slaveWebView.init(cordova, new ArrayList<PluginEntry>(), webView.getWhitelist(), webView.getExternalWhitelist(), preferences);
slaveWebView.init(cordova, new ArrayList<PluginEntry>(), preferences);
}
{
initWebView(slaveWebView, pluginIdWhitelist);
if (preferences.getBoolean("DisallowOverscroll", false)) {
slaveWebView.getView().setOverScrollMode(View.OVER_SCROLL_NEVER);
}
initWebView((CordovaWebViewEngine)slaveWebViewEngine, pluginIdWhitelist);

slaveWebView.clearCache(true);
slaveWebView.clearHistory();
slaveWebView.loadUrl(url);
View newView = (View)slaveWebView.getView().getParent();
contentView.addView(newView);
contentView.addView(slaveWebView.getView());
slaveVisible = true;
// Back button capturing breaks without these:
webView.getView().setEnabled(false);
newView.requestFocus();
slaveWebView.getView().requestFocus();
}
callbackContext.success();
}
@@ -179,13 +190,13 @@ private void destroy(CallbackContext callbackContext) {
Log.w(LOG_TAG, "destroy: already destroyed");
} else {
slaveWebView.loadUrl("data:text/plain;charset=utf-8,");
contentView.removeView((View)slaveWebView.getView().getParent());
contentView.removeView(slaveWebView.getView());
webView.getView().setEnabled(true);
origMainView.requestFocus();
webView.getView().requestFocus();

slaveWebView.getView().setScaleX(1.0f);
slaveWebView.getView().setScaleY(1.0f);
slaveWebView.setStealTapEvents(false);
slaveWebViewEngine.setStealTapEvents(false);
slaveVisible = false;
sendEvent("destroyed");
}
@@ -211,14 +222,14 @@ private void setSlaveVisible(boolean value, CallbackContext callbackContext) {
anim.scaleX(1.0f).scaleY(1.0f);
webView.getView().setEnabled(false);
slaveWebView.getView().setEnabled(true);
((View)slaveWebView.getView().getParent()).requestFocus();
slaveWebView.getView().requestFocus();
} else {
anim.scaleX(.25f).scaleY(.25f);
webView.getView().setEnabled(true);
slaveWebView.getView().setEnabled(false);
origMainView.requestFocus();
webView.getView().requestFocus();
}
slaveWebView.setStealTapEvents(!value);
slaveWebViewEngine.setStealTapEvents(!value);
anim.setDuration(300).setInterpolator(new DecelerateInterpolator(2.0f)).start();
}
if (callbackContext != null) {
@@ -235,36 +246,47 @@ private void setPluginEntries(Set<String> pluginIdWhitelist) {
for (PluginEntry p : parser.getPluginEntries()) {
if (!pluginIdWhitelist.contains(p.service)) {
pluginEntries.remove(p);
} else if (WhitelistPlugin.class.getCanonicalName().equals(p.pluginClass)) {
// TODO: pass through path to launching config.xml.
//p.plugin = createWhitelistPlugin();
}
}
slaveWebView.getPluginManager().setPluginEntries(pluginEntries);
// This is added by cordova-android in code, so we need to re-add it likewise.
// Note that we re-route navigator.app.exitApp() in JS to close the webview rather than close the Activity.
slaveWebView.getPluginManager().addService("App", "org.apache.cordova.CoreAndroid");
slaveWebView.getPluginManager().addService("CoreAndroid", "org.apache.cordova.CoreAndroid");
}

private void initWebView(final CustomCordovaWebView newWebView, Set<String> pluginIdWhitelist) {
setPluginEntries(pluginIdWhitelist);

CordovaActivity activity = (CordovaActivity)cordova.getActivity();
if (contentView == null) {
contentView = (ViewGroup)activity.findViewById(android.R.id.content);
origMainView = contentView.getChildAt(0);
}

if(layoutView == null) {
layoutView = new LinearLayoutSoftKeyboardDetect(activity, contentView.getWidth(), contentView.getHeight());
layoutView.addView(newWebView.getView());
private CordovaPlugin createWhitelistPlugin(Uri configXml) {
InputStream istr = null;
try {
istr = webView.getResourceApi().openForRead(configXml).inputStream;
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(false);
XmlPullParser parser = factory.newPullParser();
parser.setInput(istr, "UTF-8");
return new WhitelistPlugin(parser);
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (istr != null) {
try {
istr.close();
} catch (IOException e) {
}
}
}
layoutView.setOrientation(LinearLayout.VERTICAL);
return null;
}

// layoutView.setBackground(origRootView.getBackground());
layoutView.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, Gravity.BOTTOM | Gravity.LEFT));
private void initWebView(final CordovaWebViewEngine newWebView, Set<String> pluginIdWhitelist) {
setPluginEntries(pluginIdWhitelist);

newWebView.getView().setLayoutParams(new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
newWebView.getView().setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
1.0F));
ViewGroup.LayoutParams.MATCH_PARENT));
newWebView.getView().setVisibility(View.VISIBLE);
}
}
@@ -18,65 +18,48 @@ Licensed to the Apache Software Foundation (ASF) under one
*/
package org.apache.appharness;

import org.apache.cordova.AndroidWebView;
import org.apache.cordova.engine.SystemWebView;
import org.apache.cordova.engine.SystemWebViewEngine;

import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Build;
import android.util.Log;
import android.view.MotionEvent;
import android.webkit.WebView;

class CustomAndroidWebView extends AndroidWebView implements CustomCordovaWebView {
private static final String LOG_TAG = "AppHarnessUI";
class CustomAndroidWebView extends SystemWebViewEngine implements CustomCordovaWebView {
private static final String LOG_TAG = "CustomAndroidWebView";

private AppHarnessUI parent;
TwoFingerDoubleTapGestureDetector twoFingerTapDetector;
boolean stealTapEvents;

public CustomAndroidWebView(AppHarnessUI parent, Context context) {
super(context);
super(new CustomView(context));
this.parent = parent;
((CustomView)webView).parent = this;
twoFingerTapDetector = new TwoFingerDoubleTapGestureDetector(parent);
}

@Override
public void setStealTapEvents(boolean value){
stealTapEvents=value;
}

TwoFingerDoubleTapGestureDetector twoFingerTapDetector;
boolean stealTapEvents;

@Override
public boolean onTouchEvent(MotionEvent e) {
if (stealTapEvents) {
if (e.getAction() == MotionEvent.ACTION_UP) {
parent.sendEvent("hideMenu");
}
return true;
}
twoFingerTapDetector.onTouchEvent(e);
return super.onTouchEvent(e);
}

@SuppressLint("NewApi")
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// Needed for the view to stay in the bottom when rotating.
setPivotY(h);
}

@SuppressLint("NewApi")
@Override
public void evaluateJavascript(String script) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
loadUrl("javascript:" + script);
webView.loadUrl("javascript:" + script);
} else {
((WebView)this).evaluateJavascript(script, null);
webView.evaluateJavascript(script, null);
}
}

@Override
public boolean backHistory() {
public boolean goBack() {
if (canGoBack()) {
return super.backHistory();
return super.goBack();
}
if (parent.slaveVisible) {
parent.sendEvent("showMenu");
@@ -86,4 +69,30 @@ public boolean backHistory() {
Log.w(LOG_TAG, "Somehow back button was pressed when app not visible");
return false;
}

private static class CustomView extends SystemWebView {
CustomAndroidWebView parent;
public CustomView(Context context) {
super(context);
}

@Override
public boolean onTouchEvent(MotionEvent e) {
if (parent.stealTapEvents) {
if (e.getAction() == MotionEvent.ACTION_UP) {
parent.parent.sendEvent("hideMenu");
}
return true;
}
parent.twoFingerTapDetector.onTouchEvent(e);
return super.onTouchEvent(e);
}

@SuppressLint("NewApi")
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// Needed for the view to stay in the bottom when rotating.
setPivotY(h);
}
}
}
@@ -18,9 +18,7 @@ Licensed to the Apache Software Foundation (ASF) under one
*/
package org.apache.appharness;

import org.apache.cordova.CordovaWebView;

interface CustomCordovaWebView extends CordovaWebView {
interface CustomCordovaWebView {
void setStealTapEvents(boolean value);
void evaluateJavascript(String script);
}
@@ -21,8 +21,10 @@
<name>{NAME}</name>
<content src="cdvah/harnessmenu.html" />
<access origin="*" />
<preference name="webView" value="org.apache.cordova.AndroidWebView" />
<preference name="webView" value="org.apache.cordova.engine.SystemWebViewEngine" />
<preference name="android-minSdkVersion" value="14" />
<preference name="iosPersistentFileLocation" value="Library" />
<preference name="AndroidPersistentFileLocation" value="Internal" />
<preference name="CrosswalkAnimatable" value="true" />
<preference name="LoadUrlTimeoutValue" value="0" />
</widget>
@@ -30,7 +30,7 @@
});
if (cordova.platformId == 'android') {
// This is a plugin bundled with the platform.
ret.push('App');
ret.push('CoreAndroid');
// Needed for launching to work.
ret.push('UrlRemap');
}

0 comments on commit 675a3d3

Please sign in to comment.