/* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.android.material.internal; import static androidx.core.util.Preconditions.checkNotNull; import android.os.Build; import android.os.Build.VERSION_CODES; import androidx.annotation.IntRange; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.RestrictTo; import androidx.annotation.RestrictTo.Scope; import android.text.Layout; import android.text.Layout.Alignment; import android.text.StaticLayout; import android.text.TextDirectionHeuristic; import android.text.TextDirectionHeuristics; import android.text.TextPaint; import android.text.TextUtils; import java.lang.reflect.Constructor; /** * Class to create StaticLayout using StaticLayout.Builder on API23+ and a hidden StaticLayout * constructor before that. * *
Usage: * *
{@code
* StaticLayout staticLayout =
* StaticLayoutBuilderCompat.obtain("Lorem Ipsum", new TextPaint(), 100)
* .setAlignment(Alignment.ALIGN_NORMAL)
* .build();
* }
*
* @hide
*/
@RestrictTo(Scope.LIBRARY_GROUP)
final class StaticLayoutBuilderCompat {
private static final String TEXT_DIR_CLASS = "android.text.TextDirectionHeuristic";
private static final String TEXT_DIRS_CLASS = "android.text.TextDirectionHeuristics";
private static final String TEXT_DIR_FIRSTSTRONG_LTR = "FIRSTSTRONG_LTR";
private static boolean initialized;
@Nullable private static Constructor{@code
* StaticLayout(
* CharSequence source,
* int bufstart,
* int bufend,
* TextPaint paint,
* int outerwidth,
* Alignment align,
* TextDirectionHeuristic textDir,
* float spacingmult,
* float spacingadd,
* boolean includepad,
* TextUtils.TruncateAt ellipsize,
* int ellipsizedWidth,
* int maxLines)
* }
*/
private static void createConstructorWithReflection() throws StaticLayoutBuilderCompatException {
if (initialized) {
return;
}
try {
final Class> textDirClass;
if (Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR2) {
textDirClass = TextDirectionHeuristic.class;
textDirection = TextDirectionHeuristics.FIRSTSTRONG_LTR;
} else {
ClassLoader loader = StaticLayoutBuilderCompat.class.getClassLoader();
textDirClass = loader.loadClass(TEXT_DIR_CLASS);
Class> textDirsClass = loader.loadClass(TEXT_DIRS_CLASS);
textDirection = textDirsClass.getField(TEXT_DIR_FIRSTSTRONG_LTR).get(textDirsClass);
}
final Class>[] signature =
new Class>[] {
CharSequence.class,
int.class,
int.class,
TextPaint.class,
int.class,
Alignment.class,
textDirClass,
float.class,
float.class,
boolean.class,
TextUtils.TruncateAt.class,
int.class,
int.class
};
constructor = StaticLayout.class.getDeclaredConstructor(signature);
constructor.setAccessible(true);
initialized = true;
} catch (Exception cause) {
throw new StaticLayoutBuilderCompatException(cause);
}
}
static class StaticLayoutBuilderCompatException extends Exception {
StaticLayoutBuilderCompatException(Throwable cause) {
super("Error thrown initializing StaticLayout", cause);
}
}
}