1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mobile/android/base/tests/helpers/FrameworkHelper.java Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,88 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +package org.mozilla.gecko.tests.helpers; 1.9 + 1.10 +import static org.mozilla.gecko.tests.helpers.AssertionHelper.fFail; 1.11 + 1.12 +import java.lang.reflect.Field; 1.13 + 1.14 +import android.content.Context; 1.15 +import android.view.View; 1.16 + 1.17 +/** 1.18 + * Provides helper functions for accessing Android framework features 1.19 + * 1.20 + * This class uses reflection to access framework functionalities that are 1.21 + * unavailable through the regular Android API. Using reflection in this 1.22 + * case is okay because it does not touch Gecko classes that go through 1.23 + * ProGuard. 1.24 + */ 1.25 +public final class FrameworkHelper { 1.26 + 1.27 + private FrameworkHelper() { /* To disallow instantiation. */ } 1.28 + 1.29 + private static Field getClassField(final Class<?> clazz, final String fieldName) 1.30 + throws NoSuchFieldException { 1.31 + Class<?> cls = clazz; 1.32 + do { 1.33 + try { 1.34 + return cls.getDeclaredField(fieldName); 1.35 + } catch (final NoSuchFieldException e) { 1.36 + cls = cls.getSuperclass(); 1.37 + } 1.38 + } while (cls != null); 1.39 + // We tried getDeclaredField before; now try getField instead. 1.40 + // getField behaves differently in that getField traverses the inheritance 1.41 + // list, but it only works on public fields. While getField won't get us 1.42 + // anything new, it makes code cleaner by throwing an exception for us. 1.43 + return clazz.getField(fieldName); 1.44 + } 1.45 + 1.46 + private static Object getField(final Object obj, final String fieldName) { 1.47 + try { 1.48 + final Field field = getClassField(obj.getClass(), fieldName); 1.49 + final boolean accessible = field.isAccessible(); 1.50 + field.setAccessible(true); 1.51 + final Object ret = field.get(obj); 1.52 + field.setAccessible(accessible); 1.53 + return ret; 1.54 + } catch (final NoSuchFieldException e) { 1.55 + // We expect a valid field name; if it's not valid, 1.56 + // the caller is doing something wrong and should be fixed. 1.57 + fFail("Argument field should be a valid field name: " + e.toString()); 1.58 + } catch (final IllegalAccessException e) { 1.59 + // This should not happen. If it does, setAccessible above is not working. 1.60 + fFail("Field should be accessible: " + e.toString()); 1.61 + } 1.62 + throw new IllegalStateException("Should not continue from previous failures"); 1.63 + } 1.64 + 1.65 + private static void setField(final Object obj, final String fieldName, final Object value) { 1.66 + try { 1.67 + final Field field = getClassField(obj.getClass(), fieldName); 1.68 + final boolean accessible = field.isAccessible(); 1.69 + field.setAccessible(true); 1.70 + field.set(obj, value); 1.71 + field.setAccessible(accessible); 1.72 + return; 1.73 + } catch (final NoSuchFieldException e) { 1.74 + // We expect a valid field name; if it's not valid, 1.75 + // the caller is doing something wrong and should be fixed. 1.76 + fFail("Argument field should be a valid field name: " + e.toString()); 1.77 + } catch (final IllegalAccessException e) { 1.78 + // This should not happen. If it does, setAccessible above is not working. 1.79 + fFail("Field should be accessible: " + e.toString()); 1.80 + } 1.81 + throw new IllegalStateException("Cannot continue from previous failures"); 1.82 + } 1.83 + 1.84 + public static Context getViewContext(final View v) { 1.85 + return (Context) getField(v, "mContext"); 1.86 + } 1.87 + 1.88 + public static void setViewContext(final View v, final Context c) { 1.89 + setField(v, "mContext", c); 1.90 + } 1.91 +}