public static GestureTrailTheme fromThemeResource(
      @NonNull Context askContext,
      @NonNull Context themeContext,
      @NonNull AddOn.AddOnResourceMapping mapper,
      @StyleRes int resId) {

    // filling in the defaults
    TypedArray defaultValues =
        askContext.obtainStyledAttributes(
            R.style.AnyKeyboardGestureTrailTheme, R.styleable.GestureTypingTheme);
    int maxTrailLength =
        defaultValues.getInt(R.styleable.GestureTypingTheme_gestureTrailMaxSectionsLength, 32);
    @ColorInt
    int trailStartColor =
        defaultValues.getColor(R.styleable.GestureTypingTheme_gestureTrailStartColor, Color.BLUE);
    @ColorInt
    int trailEndColor =
        defaultValues.getColor(R.styleable.GestureTypingTheme_gestureTrailEndColor, Color.BLACK);
    float startStrokeSize =
        defaultValues.getDimension(R.styleable.GestureTypingTheme_gestureTrailStartStrokeSize, 0f);
    float endStrokeSize =
        defaultValues.getDimension(R.styleable.GestureTypingTheme_gestureTrailEndStrokeSize, 0f);
    defaultValues.recycle();

    final int[] remoteStyleableArray =
        mapper.getRemoteStyleableArrayFromLocal(R.styleable.GestureTypingTheme);
    TypedArray a = themeContext.obtainStyledAttributes(resId, remoteStyleableArray);
    final int resolvedAttrsCount = a.getIndexCount();
    for (int attrIndex = 0; attrIndex < resolvedAttrsCount; attrIndex++) {
      final int remoteIndex = a.getIndex(attrIndex);
      try {
        int localAttrId = mapper.getLocalAttrId(remoteStyleableArray[remoteIndex]);
        if (localAttrId == R.attr.gestureTrailMaxSectionsLength)
          maxTrailLength = a.getInt(remoteIndex, maxTrailLength);
        else if (localAttrId == R.attr.gestureTrailStartColor)
          trailStartColor = a.getColor(remoteIndex, trailStartColor);
        else if (localAttrId == R.attr.gestureTrailEndColor)
          trailEndColor = a.getColor(remoteIndex, trailEndColor);
        else if (localAttrId == R.attr.gestureTrailStartStrokeSize)
          startStrokeSize = a.getDimension(remoteIndex, startStrokeSize);
        else if (localAttrId == R.attr.gestureTrailEndStrokeSize)
          endStrokeSize = a.getDimension(remoteIndex, endStrokeSize);
      } catch (Exception e) {
        Logger.w("ASK_GESTURE_THEME", "Got an exception while reading gesture theme data", e);
      }
    }
    a.recycle();

    return new GestureTrailTheme(
        trailStartColor, trailEndColor, startStrokeSize, endStrokeSize, maxTrailLength);
  }
@Test
  public void testFromThemeResource() {
    GestureTrailTheme underTest =
        GestureTrailTheme.fromThemeResource(
            ApplicationProvider.getApplicationContext(),
            ApplicationProvider.getApplicationContext(),
            new AddOn.AddOnResourceMapping() {
              @Override
              public int[] getRemoteStyleableArrayFromLocal(int[] localStyleableArray) {
                return localStyleableArray;
              }

              @Override
              public int getApiVersion() {
                return 10;
              }

              @Override
              public int getLocalAttrId(int remoteAttrId) {
                return remoteAttrId;
              }
            },
            R.style.AnyKeyboardGestureTrailTheme);

    Assert.assertEquals(64, underTest.maxTrailLength);
    Assert.assertEquals(Color.parseColor("#5555ddff"), underTest.mTrailStartColor);
    Assert.assertEquals(Color.parseColor("#11116622"), underTest.mTrailEndColor);
    Assert.assertEquals(8f, underTest.mStartStrokeSize, 0.1f);
    Assert.assertEquals(2f, underTest.mEndStrokeSize, 0.1f);
    Assert.assertEquals(1 / 64f, underTest.mTrailFraction, 0.1f);
  }