feat(android): Add API for checking Chrome version

This commit is contained in:
Darcy Wong 2021-07-29 14:22:13 +07:00
parent fc2d0ccd4d
commit ca2a7c2ef4
9 changed files with 193 additions and 48 deletions

View file

@ -24,7 +24,7 @@ import com.tavultesoft.kmea.BaseActivity;
import com.tavultesoft.kmea.KMManager;
import com.tavultesoft.kmea.util.KMPLink;
import com.tavultesoft.kmea.util.KMString;
import com.tavultesoft.kmea.util.WebViewUtil;
import com.tavultesoft.kmea.util.WebViewUtils;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -166,7 +166,7 @@ public class KMPBrowserActivity extends BaseActivity {
@Override
protected void onDestroy() {
super.onDestroy();
WebViewUtil.cleanup(webView);
WebViewUtils.cleanup(webView);
}
@Override

View file

@ -40,6 +40,8 @@ import com.keyman.android.DownloadIntentService;
import com.tavultesoft.kmea.util.KMLog;
import com.tavultesoft.kmea.util.KMPLink;
import com.tavultesoft.kmea.util.KMString;
import com.tavultesoft.kmea.util.WebViewUtils;
import com.tavultesoft.kmea.util.WebViewUtils.EngineModeType;
import android.Manifest;
import android.app.ProgressDialog;
@ -197,6 +199,7 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
textView.setTextSize((float) textSize);
textView.setSelection(textView.getText().length());
checkChromeVersion();
CheckInstallReferrer.checkGooglePlayInstallReferrer(this, context);
checkGetStarted();
}
@ -764,6 +767,24 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
KMManager.setMaySendCrashReport(maySendCrashReport);
}
private void checkChromeVersion() {
if (WebViewUtils.getEngineModeType(context,"") != EngineModeType.ENGINE_MODE_TYPE_FULL) {
// Notify minimum Chrome version needed
String message = "Minimum Chrome version 57 needed for Keyman.";
//KMLog.LogError(TAG, message);
Toast.makeText(getApplicationContext(), message,
Toast.LENGTH_LONG).show();
// Launch PlayStore to update Chrome
try {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=com.android.chrome"));
startActivity(intent);
} catch (android.content.ActivityNotFoundException e) {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/apps/details?id=com.android.chome")));
}
}
}
private Uri requestPermissionIntentUri;
@Override

View file

@ -14,7 +14,7 @@ import com.stepstone.stepper.StepperLayout;
import com.stepstone.stepper.VerificationError;
import com.tavultesoft.kmea.packages.PackageProcessor;
import com.tavultesoft.kmea.util.FileUtils;
import com.tavultesoft.kmea.util.WebViewUtil;
import com.tavultesoft.kmea.util.WebViewUtils;
import android.graphics.Bitmap;
import android.os.Bundle;
@ -137,7 +137,7 @@ public class WebViewFragment extends Fragment implements BlockingStep {
@Override
public void onPageFinished(WebView view, String url) {
// Inject a meta viewport tag into the head of the file if it doesn't exist
WebViewUtil.injectViewport(view);
WebViewUtils.injectViewport(view);
}
});

View file

@ -4,6 +4,10 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.VIBRATE" />
<queries>
<!-- Permission needed to query for Chrome version -->
<package android:name="com.android.chrome" />
</queries>
<application
android:theme="@style/AppTheme" >

View file

@ -31,7 +31,7 @@ import com.tavultesoft.kmea.packages.PackageProcessor;
import com.tavultesoft.kmea.util.FileProviderUtils;
import com.tavultesoft.kmea.util.FileUtils;
import com.tavultesoft.kmea.util.HelpFile;
import com.tavultesoft.kmea.util.WebViewUtil;
import com.tavultesoft.kmea.util.WebViewUtils;
import java.io.File;
@ -144,7 +144,7 @@ public class KMHelpFileActivity extends BaseActivity {
@Override
public void onPageFinished(WebView view, String url) {
// Inject a meta viewport tag into the head of the file if it doesn't exist
WebViewUtil.injectViewport(view);
WebViewUtils.injectViewport(view);
}
});
@ -167,7 +167,7 @@ public class KMHelpFileActivity extends BaseActivity {
@Override
protected void onDestroy() {
super.onDestroy();
WebViewUtil.cleanup(webView);
WebViewUtils.cleanup(webView);
}
@Override

View file

@ -75,6 +75,7 @@ import com.tavultesoft.kmea.util.FileUtils;
import com.tavultesoft.kmea.util.KMLog;
import com.tavultesoft.kmea.util.KMString;
import com.tavultesoft.kmea.util.MapCompat;
import com.tavultesoft.kmea.util.WebViewUtils;
import org.json.JSONArray;
import org.json.JSONException;
@ -367,6 +368,15 @@ public final class KMManager {
return appVersion;
}
/**
* Get the Keyman Engine mode based on the Chrome version
* @param aContext
* @return WebViewUtils.EngineModeType
*/
public static WebViewUtils.EngineModeType getEngineMode(Context aContext) {
return WebViewUtils.getEngineModeType(aContext, "");
}
// Check if a keyboard namespace is reserved
public static boolean isReservedNamespace(String packageID) {
if (packageID.equals(KMDefault_UndefinedPackageID)) {

View file

@ -1,41 +0,0 @@
/**
* Copyright (C) 2021 SIL International. All rights reserved.
*/
package com.tavultesoft.kmea.util;
import android.view.ViewGroup;
import android.webkit.WebView;
public final class WebViewUtil {
// Inject a meta viewport tag into the head of the file if it doesn't exist
public static void injectViewport(WebView webView) {
if (webView != null) {
webView.loadUrl(
"javascript:(function() {" +
"if(document.head && !document.querySelectorAll('meta[name=viewport]').length) {"+
"let meta=document.createElement('meta');"+
"meta.name='viewport';"+
"meta.content='width=device-width, initial-scale=1';"+
"document.head.appendChild(meta);"+
"}"+
"})()"
);
}
}
// Blank the webView and destroy completely
// Reference: https://stackoverflow.com/questions/17418503/destroy-webview-in-android/17458577#17458577
public static void cleanup(WebView webView) {
if (webView != null) {
webView.loadUrl("about:blank");
ViewGroup viewGroup = (ViewGroup) webView.getParent();
if (viewGroup != null) {
viewGroup.removeView(webView);
}
webView.removeAllViews();
webView.destroy();
webView = null;
}
}
}

View file

@ -0,0 +1,98 @@
/**
* Keyman is copyright (C) SIL International. MIT License.
*/
package com.tavultesoft.kmea.util;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.view.ViewGroup;
import android.webkit.WebView;
import com.tavultesoft.kmea.util.KMLog;
public final class WebViewUtils {
public static final String TAG = "WebViewUtils";
// Keyman Engine functionality based on Chrome version
public enum EngineModeType {
ENGINE_MODE_TYPE_DISABLED, // WebView doesn't support touch keyboard features
ENGINE_MODE_TYPE_DEGRADED, // WebView supports touch keyboards but not LDML keyboards
ENGINE_MODE_TYPE_FULL; // WebView supports touch keyboards and LDML keyboards
}
/**
* Get the Keyman Engine mode based on the Chrome version.
* @param context - The context
* @param chromeVersion - String of the device's Chrome version.
* If not provided, the device's Chrome version is queried
* @return EngineModeType
*/
public static EngineModeType getEngineModeType(Context context, String chromeVersion) {
if (context == null) {
return EngineModeType.ENGINE_MODE_TYPE_DISABLED;
}
if (chromeVersion == null || chromeVersion.isEmpty()) {
chromeVersion = getChromeVersion(context);
}
if (FileUtils.compareVersions(chromeVersion, "57.0") == FileUtils.VERSION_GREATER) {
return EngineModeType.ENGINE_MODE_TYPE_FULL;
} else if (FileUtils.compareVersions(chromeVersion, "37.0") == FileUtils.VERSION_GREATER) {
return EngineModeType.ENGINE_MODE_TYPE_DEGRADED;
}
return EngineModeType.ENGINE_MODE_TYPE_DISABLED;
}
// Inject a meta viewport tag into the head of the file if it doesn't exist
public static void injectViewport(WebView webView) {
if (webView != null) {
webView.loadUrl(
"javascript:(function() {" +
"if(document.head && !document.querySelectorAll('meta[name=viewport]').length) {"+
"let meta=document.createElement('meta');"+
"meta.name='viewport';"+
"meta.content='width=device-width, initial-scale=1';"+
"document.head.appendChild(meta);"+
"}"+
"})()"
);
}
}
// Blank the webView and destroy completely
// Reference: https://stackoverflow.com/questions/17418503/destroy-webview-in-android/17458577#17458577
public static void cleanup(WebView webView) {
if (webView != null) {
webView.loadUrl("about:blank");
ViewGroup viewGroup = (ViewGroup) webView.getParent();
if (viewGroup != null) {
viewGroup.removeView(webView);
}
webView.removeAllViews();
webView.destroy();
webView = null;
}
}
/**
* Get the Chrome version. Returns empty string if Chrome not installed.
* @param context - The context
* @return String
*/
private static String getChromeVersion(Context context) {
if (context == null) {
return "";
}
try {
PackageInfo pInfo;
pInfo = context.getPackageManager().getPackageInfo("com.android.chrome", PackageManager.GET_ACTIVITIES);
if (pInfo != null) {
return pInfo.versionName;
}
} catch (PackageManager.NameNotFoundException e) {
KMLog.LogInfo(TAG, "Chrome not installed");
}
return "";
}
}

View file

@ -0,0 +1,53 @@
/**
* Keyman is copyright (C) SIL International. MIT License.
*/
package com.tavultesoft.kmea.util;
import android.content.Context;
import androidx.test.core.app.ApplicationProvider;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import com.tavultesoft.kmea.util.WebViewUtils;
@RunWith(RobolectricTestRunner.class)
public class WebViewUtilsTest {
private Context context = null;
@Before
public void getContext() {
context = ApplicationProvider.getApplicationContext();
}
@Test
public void test_ChromeEmpty_EngineModeTypeDisabled() {
String chromeVersion = "";
Assert.assertEquals(WebViewUtils.getEngineModeType(context, chromeVersion),
WebViewUtils.EngineModeType.ENGINE_MODE_TYPE_DISABLED);
}
@Test
public void test_Chrome36_EngineModeTypeDisabled() {
String chromeVersion = "36.0";
Assert.assertEquals(WebViewUtils.getEngineModeType(context, chromeVersion),
WebViewUtils.EngineModeType.ENGINE_MODE_TYPE_DISABLED);
}
@Test
public void test_Chrome57_EngineModeTypeDegraded() {
String chromeVersion = "57.0";
Assert.assertEquals(WebViewUtils.getEngineModeType(context, chromeVersion),
WebViewUtils.EngineModeType.ENGINE_MODE_TYPE_DEGRADED);
}
@Test
public void test_Chrome58_EngineModeTypeFull() {
String chromeVersion = "58.0";
Assert.assertEquals(WebViewUtils.getEngineModeType(context, chromeVersion),
WebViewUtils.EngineModeType.ENGINE_MODE_TYPE_FULL);
}
}