1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.compatibility.common.util;
18 
19 import android.content.Context;
20 import android.content.pm.PackageManager;
21 
22 /**
23  * Utilities to enable the android.webkit.* CTS tests (and others that rely on a functioning
24  * android.webkit.WebView implementation) to determine whether a functioning WebView is present
25  * on the device or not.
26  *
27  * Test cases that require android.webkit.* classes should wrap their first usage of WebView in a
28  * try catch block, and pass any exception that is thrown to
29  * NullWebViewUtils.determineIfWebViewAvailable. The return value of
30  * NullWebViewUtils.isWebViewAvailable will then determine if the test should expect to be able to
31  * use a WebView.
32  */
33 public class NullWebViewUtils {
34 
35     private static boolean sWebViewUnavailable;
36 
37     /**
38      * @param context Current Activity context, used to query the PackageManager.
39      * @param t       An exception thrown by trying to invoke android.webkit.* APIs.
40      */
determineIfWebViewAvailable(Context context, Throwable t)41     public static void determineIfWebViewAvailable(Context context, Throwable t) {
42         sWebViewUnavailable = !hasWebViewFeature(context) && checkCauseWasUnsupportedOperation(t);
43     }
44 
45     /**
46      * After calling determineIfWebViewAvailable, this returns whether a WebView is available on the
47      * device and wheter the test can rely on it.
48      * @return True iff. PackageManager determined that there is no WebView on the device and the
49      *         exception thrown from android.webkit.* was UnsupportedOperationException.
50      */
isWebViewAvailable()51     public static boolean isWebViewAvailable() {
52         return !sWebViewUnavailable;
53     }
54 
hasWebViewFeature(Context context)55     private static boolean hasWebViewFeature(Context context) {
56         // Query the system property that determins if there is a functional WebView on the device.
57         PackageManager pm = context.getPackageManager();
58         return pm.hasSystemFeature(PackageManager.FEATURE_WEBVIEW);
59     }
60 
checkCauseWasUnsupportedOperation(Throwable t)61     private static boolean checkCauseWasUnsupportedOperation(Throwable t) {
62         if (t == null) return false;
63         while (t.getCause() != null) {
64             t = t.getCause();
65         }
66         return t instanceof UnsupportedOperationException;
67     }
68 
69     /**
70      * Some CTS tests (by design) first use android.webkit.* from a background thread. This helper
71      * allows the test to catch the UnsupportedOperationException from that background thread, and
72      * then query the result from the test main thread.
73      */
74     public static class NullWebViewFromThreadExceptionHandler
75             implements Thread.UncaughtExceptionHandler {
76         private Throwable mPendingException;
77 
78         @Override
uncaughtException(Thread t, Throwable e)79         public void uncaughtException(Thread t, Throwable e) {
80             mPendingException = e;
81         }
82 
isWebViewAvailable(Context context)83         public boolean isWebViewAvailable(Context context) {
84             return hasWebViewFeature(context) ||
85                     !checkCauseWasUnsupportedOperation(mPendingException);
86         }
87     }
88 }
89