
com.reandroid.arsc.value.ResConfig Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ARSCLib Show documentation
Show all versions of ARSCLib Show documentation
Android binary resources read/write library
/*
* Copyright (C) 2022 github.com/REAndroid
*
* 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.reandroid.arsc.value;
import com.reandroid.arsc.base.Block;
import com.reandroid.arsc.container.FixedBlockContainer;
import com.reandroid.arsc.io.BlockLoad;
import com.reandroid.arsc.io.BlockReader;
import com.reandroid.arsc.item.ByteArray;
import com.reandroid.arsc.item.IntegerItem;
import com.reandroid.json.JSONConvert;
import com.reandroid.json.JSONObject;
import java.io.IOException;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ResConfig extends FixedBlockContainer
implements BlockLoad, JSONConvert, Comparable {
private final IntegerItem configSize;
private final ByteArray mValuesContainer;
private String mQualifiers;
private int mQualifiersStamp;
public ResConfig(){
this(SIZE_64);
}
private ResConfig(int size){
super(2);
this.configSize = new IntegerItem(size);
this.mValuesContainer = new ByteArray(size - 4);
addChild(0, configSize);
addChild(1, mValuesContainer);
this.configSize.setBlockLoad(this);
this.mQualifiersStamp = 0;
}
public boolean isEqualOrMoreSpecificThan(ResConfig resConfig){
if(resConfig == null){
return false;
}
if(resConfig == this || resConfig.isDefault()){
return true;
}
byte[] bytes = ByteArray.trimTrailZeros(this.mValuesContainer.getBytes());
byte[] otherBytes = ByteArray.trimTrailZeros(resConfig.mValuesContainer.getBytes());
int max = otherBytes.length;
if(max > bytes.length){
return false;
}
for(int i = 0; i> 5) + ((in0 & 0x03) << 3));
byte third = (byte) ((in0 & 0x7c) >> 2);
out[0] = (char) (first + base);
out[1] = (char) (second + base);
out[2] = (char) (third + base);
}else if (in0 != 0) {
out = new char[2];
out[0] = (char) in0;
out[1] = (char) in1;
}else {
out = new char[2];
}
return out;
}
private static byte[] packLanguage(char[] language) {
return packLanguageOrRegion(language, 'a');
}
private static byte[] packRegion(char[] region) {
return packLanguageOrRegion(region, '0');
}
private static byte[] packLanguageOrRegion(char[] in, char base) {
byte[] out = new byte[2];
if(in == null || in.length<2){
return out;
}
if (in.length == 2 || in[2] == 0 || in[2] == '-') {
out[0] = (byte) in[0];
out[1] = (byte) in[1];
} else {
byte first = (byte) ((in[0] - base) & 0x007f);
byte second = (byte) ((in[1] - base) & 0x007f);
byte third = (byte) ((in[2] - base) & 0x007f);
out[0] = (byte) (0x80 | (third << 2) | (second >> 3));
out[1] = (byte) ((second << 5) | first);
}
return out;
}
private static byte[] toByteArray(char[] chs, int len){
byte[] bts = new byte[len];
if(chs == null){
return bts;
}
int sz = chs.length;
for(int i = 0; i < sz; i++){
bts[i]= (byte) chs[i];
}
return bts;
}
private static char[] toCharArray(byte[] bts){
if(isNull(bts)){
return null;
}
int sz = bts.length;
char[] chs = new char[sz];
for(int i = 0; i < sz; i++){
int val = 0xff & bts[i];
chs[i]= (char) val;
}
return chs;
}
private static char[] trimEndingZero(char[] chars){
if(chars == null){
return null;
}
int lastNonZero = -1;
for(int i = 0; i < chars.length; i++){
if(chars[i]!= 0){
lastNonZero = i;
}
}
if(lastNonZero==-1){
return null;
}
lastNonZero = lastNonZero+1;
if(lastNonZero== chars.length){
return chars;
}
char[] result = new char[lastNonZero];
System.arraycopy(chars, 0, result, 0, lastNonZero);
return result;
}
private static boolean isNull(char[] chs){
if(chs == null){
return true;
}
for(int i = 0; i < chs.length; i++){
if(chs[i]!= 0){
return false;
}
}
return true;
}
private static boolean isNull(byte[] bts){
if(bts == null){
return true;
}
for(int i = 0; i < bts.length; i++){
if(bts[i] != 0){
return false;
}
}
return true;
}
private static byte[] ensureArrayLength(byte[] bts, int length){
if(bts == null || length == 0){
return new byte[length];
}
if(bts.length == length){
return bts;
}
byte[] result = new byte[length];
int max = result.length;
if(bts.length < max){
max = bts.length;
}
System.arraycopy(bts, 0, result, 0, max);
return result;
}
private static String ensureLength(String str, int min, char postfix){
int length = str.length();
if(length >= min){
return str;
}
StringBuilder builder = new StringBuilder();
builder.append(str);
int remain = min - length;
for(int i = 0; i < remain; i++){
builder.append(postfix);
}
return builder.toString();
}
private static String trimPostfix(String str, char postfix){
if(str == null){
return null;
}
int length = str.length();
int index = length-1;
while (length>0 && str.charAt(index) == postfix){
str = str.substring(0, index);
length = str.length();
index = length - 1;
}
return str;
}
public static boolean isValidSize(int size){
switch (size){
case SIZE_16:
case SIZE_28:
case SIZE_32:
case SIZE_36:
case SIZE_48:
case SIZE_52:
case SIZE_56:
case SIZE_64:
return true;
default:
return size > SIZE_64;
}
}
public static final class Orientation extends Flag{
public static final int MASK = 0x0f;
public static final Orientation PORT = new Orientation("port", 0x01);
public static final Orientation LAND = new Orientation("land", 0x02);
public static final Orientation SQUARE = new Orientation("square", 0x03);
public static final Orientation[] VALUES = new Orientation[]{
PORT,
LAND,
SQUARE
};
private Orientation(String name, int flag) {
super(name, flag);
}
public static Orientation valueOf(int flag){
return Flag.valueOf(VALUES, MASK, flag);
}
public static Orientation valueOf(String name){
return Flag.valueOf(VALUES, name);
}
public static Orientation fromQualifiers(String qualifiers){
return Flag.fromQualifiers(VALUES, qualifiers);
}
public static Orientation fromQualifiers(String[] qualifiers){
return Flag.fromQualifiers(VALUES, qualifiers);
}
public static int update(Orientation flag, int value){
return Flag.update(MASK, flag, value);
}
}
public static final class Touchscreen extends Flag{
public static final int MASK = 0x0f;
public static final Touchscreen NOTOUCH = new Touchscreen("notouch", 0x01);
public static final Touchscreen STYLUS = new Touchscreen("stylus", 0x02);
public static final Touchscreen FINGER = new Touchscreen("finger", 0x03);
public static final Touchscreen[] VALUES = new Touchscreen[]{
NOTOUCH,
STYLUS,
FINGER
};
private Touchscreen(String name, int flag) {
super(name, flag);
}
public static Touchscreen valueOf(int flag){
return Flag.valueOf(VALUES, MASK, flag);
}
public static Touchscreen valueOf(String name){
return Flag.valueOf(VALUES, name);
}
public static Touchscreen fromQualifiers(String qualifiers){
return Flag.fromQualifiers(VALUES, qualifiers);
}
public static Touchscreen fromQualifiers(String[] qualifiers){
return Flag.fromQualifiers(VALUES, qualifiers);
}
public static int update(Touchscreen flag, int value){
return Flag.update(MASK, flag, value);
}
}
public static final class Density extends Flag{
public static final int MASK = 0xffff;
public static final Density LDPI = new Density("ldpi", 120);
public static final Density MDPI = new Density("mdpi", 160);
public static final Density TVDPI = new Density("tvdpi", 213);
public static final Density HDPI = new Density("hdpi", 240);
public static final Density XHDPI = new Density("xhdpi", 320);
public static final Density XXHDPI = new Density("xxhdpi", 480);
public static final Density XXXHDPI = new Density("xxxhdpi", 640);
public static final Density ANYDPI = new Density("anydpi", 0xfffe);
public static final Density NODPI = new Density("nodpi", 0xffff);
public static final Density[] VALUES = new Density[]{LDPI,
MDPI,
TVDPI,
HDPI,
XHDPI,
XXHDPI,
XXXHDPI,
ANYDPI,
NODPI
};
private Density(String name, int flag) {
super(name, flag);
}
public static Density valueOf(int flag){
if(flag== 0){
return null;
}
Density density = Flag.valueOf(VALUES, MASK, flag);
if(density == null){
flag = flag & MASK;
density = new Density(flag+"dpi", flag);
}
return density;
}
public static Density valueOf(String name){
if(name == null || name.length() < 4){
return null;
}
name = name.toLowerCase();
if(name.charAt(0) == '-'){
name = name.substring(1);
}
Density density = Flag.valueOf(VALUES, name);
if(density == null && name.endsWith("dpi")){
name = name.substring(0, name.length()-3);
try{
int flag = Integer.parseInt(name);
density = new Density(flag+"dpi", flag);
}catch (NumberFormatException ignored){
}
}
return density;
}
public static Density fromQualifiers(String qualifiers){
return fromQualifiers(qualifiers.split("\\s*-\\s*"));
}
public static Density fromQualifiers(String[] qualifiers){
if(qualifiers == null){
return null;
}
for(int i = 0; i < qualifiers.length; i++){
Density density = valueOf(qualifiers[i]);
if(density== null){
continue;
}
qualifiers[i] = null;
return density;
}
return null;
}
public static int update(Density flag, int value){
return Flag.update(MASK, flag, value);
}
}
public static final class Keyboard extends Flag{
public static final int MASK = 0x0f;
public static final Keyboard NOKEYS = new Keyboard("nokeys", 0x01);
public static final Keyboard QWERTY = new Keyboard("qwerty", 0x02);
public static final Keyboard KEY12 = new Keyboard("12key", 0x03);
public static final Keyboard[] VALUES = new Keyboard[]{
NOKEYS,
QWERTY,
KEY12
};
private Keyboard(String name, int flag) {
super(name, flag);
}
public static Keyboard valueOf(int flag){
return Flag.valueOf(VALUES, MASK, flag);
}
public static Keyboard valueOf(String name){
return Flag.valueOf(VALUES, name);
}
public static Keyboard fromQualifiers(String qualifiers){
return Flag.fromQualifiers(VALUES, qualifiers);
}
public static Keyboard fromQualifiers(String[] qualifiers){
return Flag.fromQualifiers(VALUES, qualifiers);
}
public static int update(Keyboard flag, int value){
return Flag.update(MASK, flag, value);
}
}
public static final class Navigation extends Flag{
public static final int MASK = 0x0f;
public static final Navigation NONAV = new Navigation("nonav", 0x01);
public static final Navigation DPAD = new Navigation("dpad", 0x02);
public static final Navigation TRACKBALL = new Navigation("trackball", 0x03);
public static final Navigation WHEEL = new Navigation("wheel", 0x04);
public static final Navigation[] VALUES = new Navigation[]{
NONAV,
DPAD,
TRACKBALL,
WHEEL
};
private Navigation(String name, int flag) {
super(name, flag);
}
public static Navigation valueOf(int flag){
return Flag.valueOf(VALUES, MASK, flag);
}
public static Navigation valueOf(String name){
return Flag.valueOf(VALUES, name);
}
public static Navigation fromQualifiers(String qualifiers){
return Flag.fromQualifiers(VALUES, qualifiers);
}
public static Navigation fromQualifiers(String[] qualifiers){
return Flag.fromQualifiers(VALUES, qualifiers);
}
public static int update(Navigation flag, int value){
return Flag.update(MASK, flag, value);
}
}
public static final class InputFlagsKeysHidden extends Flag{
public static final int MASK = 0x03;
public static final InputFlagsKeysHidden KEYSEXPOSED = new InputFlagsKeysHidden("keysexposed", 0x01);
public static final InputFlagsKeysHidden KEYSHIDDEN = new InputFlagsKeysHidden("keyshidden", 0x02);
public static final InputFlagsKeysHidden KEYSSOFT = new InputFlagsKeysHidden("keyssoft", 0x03);
public static final InputFlagsKeysHidden[] VALUES = new InputFlagsKeysHidden[]{
KEYSEXPOSED,
KEYSHIDDEN,
KEYSSOFT
};
private InputFlagsKeysHidden(String name, int flag) {
super(name, flag);
}
public static InputFlagsKeysHidden valueOf(int flag){
return Flag.valueOf(VALUES, MASK, flag);
}
public static InputFlagsKeysHidden valueOf(String name){
return Flag.valueOf(VALUES, name);
}
public static InputFlagsKeysHidden fromQualifiers(String qualifiers){
return Flag.fromQualifiers(VALUES, qualifiers);
}
public static InputFlagsKeysHidden fromQualifiers(String[] qualifiers){
return Flag.fromQualifiers(VALUES, qualifiers);
}
public static int update(InputFlagsKeysHidden flag, int value){
return Flag.update(MASK, flag, value);
}
}
public static final class InputFlagsNavHidden extends Flag{
public static final int MASK = 0x0C;
public static final InputFlagsNavHidden NAVEXPOSED = new InputFlagsNavHidden("navexposed", 0x04);
public static final InputFlagsNavHidden NAVHIDDEN = new InputFlagsNavHidden("navhidden", 0x08);
public static final InputFlagsNavHidden[] VALUES = new InputFlagsNavHidden[]{
NAVEXPOSED,
NAVHIDDEN
};
private InputFlagsNavHidden(String name, int flag) {
super(name, flag);
}
public static InputFlagsNavHidden valueOf(int flag){
return Flag.valueOf(VALUES, MASK, flag);
}
public static InputFlagsNavHidden valueOf(String name){
return Flag.valueOf(VALUES, name);
}
public static InputFlagsNavHidden fromQualifiers(String qualifiers){
return Flag.fromQualifiers(VALUES, qualifiers);
}
public static InputFlagsNavHidden fromQualifiers(String[] qualifiers){
return Flag.fromQualifiers(VALUES, qualifiers);
}
public static int update(InputFlagsNavHidden flag, int value){
return Flag.update(MASK, flag, value);
}
}
public static final class UiModeType extends Flag{
public static final int MASK = 0x0f;
public static final UiModeType NORMAL = new UiModeType("normal", 0x01);
public static final UiModeType DESK = new UiModeType("desk", 0x02);
public static final UiModeType CAR = new UiModeType("car", 0x03);
public static final UiModeType TELEVISION = new UiModeType("television", 0x04);
public static final UiModeType APPLIANCE = new UiModeType("appliance", 0x05);
public static final UiModeType WATCH = new UiModeType("watch", 0x06);
public static final UiModeType VRHEADSET = new UiModeType("vrheadset", 0x07);
public static final UiModeType GODZILLAUI = new UiModeType("godzillaui", 0x0b);
public static final UiModeType SMALLUI = new UiModeType("smallui", 0x0c);
public static final UiModeType MEDIUMUI = new UiModeType("mediumui", 0x0d);
public static final UiModeType LARGEUI = new UiModeType("largeui", 0x0e);
public static final UiModeType HUGEUI = new UiModeType("hugeui", 0x0f);
private static final UiModeType[] VALUES = new UiModeType[]{
NORMAL,
DESK,
CAR,
TELEVISION,
APPLIANCE,
WATCH,
VRHEADSET,
GODZILLAUI,
SMALLUI,
MEDIUMUI,
LARGEUI,
HUGEUI
};
private UiModeType(String name, int flag) {
super(name, flag);
}
public static UiModeType valueOf(int flag){
return Flag.valueOf(VALUES, MASK, flag);
}
public static UiModeType valueOf(String name){
return Flag.valueOf(VALUES, name);
}
public static UiModeType fromQualifiers(String qualifiers){
return Flag.fromQualifiers(VALUES, qualifiers);
}
public static UiModeType fromQualifiers(String[] qualifiers){
return Flag.fromQualifiers(VALUES, qualifiers);
}
public static int update(UiModeType flag, int value){
return Flag.update(MASK, flag, value);
}
}
public static final class UiModeNight extends Flag{
public static final int MASK = 0x30;
public static final UiModeNight NOTNIGHT = new UiModeNight("notnight",0x10);
public static final UiModeNight NIGHT = new UiModeNight("night",0x20);
private static final UiModeNight[] VALUES = new UiModeNight[]{
NOTNIGHT,
NIGHT
};
private UiModeNight(String name, int flag) {
super(name, flag);
}
public static UiModeNight valueOf(int flag){
return Flag.valueOf(VALUES, MASK, flag);
}
public static UiModeNight valueOf(String name){
return Flag.valueOf(VALUES, name);
}
public static UiModeNight fromQualifiers(String qualifiers){
return Flag.fromQualifiers(VALUES, qualifiers);
}
public static UiModeNight fromQualifiers(String[] qualifiers){
return Flag.fromQualifiers(VALUES, qualifiers);
}
public static int update(UiModeNight flag, int value){
return Flag.update(MASK, flag, value);
}
}
public static final class ScreenLayoutSize extends Flag{
public static final int MASK = 0x0f;
public static final ScreenLayoutSize SMALL = new ScreenLayoutSize("small", 0x01);
public static final ScreenLayoutSize NORMAL = new ScreenLayoutSize("normal", 0x02);
public static final ScreenLayoutSize LARGE = new ScreenLayoutSize("large", 0x03);
public static final ScreenLayoutSize XLARGE = new ScreenLayoutSize("xlarge", 0x04);
public static final ScreenLayoutSize[] VALUES = new ScreenLayoutSize[]{
SMALL,
NORMAL,
LARGE,
XLARGE
};
private ScreenLayoutSize(String name, int flag) {
super(name, flag);
}
public static ScreenLayoutSize valueOf(int flag){
return Flag.valueOf(VALUES, MASK, flag);
}
public static ScreenLayoutSize valueOf(String name){
return Flag.valueOf(VALUES, name);
}
public static ScreenLayoutSize fromQualifiers(String qualifiers){
return Flag.fromQualifiers(VALUES, qualifiers);
}
public static ScreenLayoutSize fromQualifiers(String[] qualifiers){
return Flag.fromQualifiers(VALUES, qualifiers);
}
public static int update(ScreenLayoutSize flag, int value){
return Flag.update(MASK, flag, value);
}
}
public static final class ScreenLayoutLong extends Flag{
public static final int MASK = 0x30;
public static final ScreenLayoutLong NOTLONG = new ScreenLayoutLong("notlong", 0x10);
public static final ScreenLayoutLong LONG = new ScreenLayoutLong("long", 0x20);
public static final ScreenLayoutLong[] VALUES = new ScreenLayoutLong[]{
NOTLONG,
LONG
};
private ScreenLayoutLong(String name, int flag) {
super(name, flag);
}
public static ScreenLayoutLong valueOf(int flag){
return Flag.valueOf(VALUES, MASK, flag);
}
public static ScreenLayoutLong valueOf(String name){
return Flag.valueOf(VALUES, name);
}
public static ScreenLayoutLong fromQualifiers(String qualifiers){
return Flag.fromQualifiers(VALUES, qualifiers);
}
public static ScreenLayoutLong fromQualifiers(String[] qualifiers){
return Flag.fromQualifiers(VALUES, qualifiers);
}
public static int update(ScreenLayoutLong flag, int value){
return Flag.update(MASK, flag, value);
}
}
public static final class ScreenLayoutDir extends Flag{
public static final int MASK = 0xC0;
public static final ScreenLayoutDir LDLTR = new ScreenLayoutDir("ldltr", 0x40);
public static final ScreenLayoutDir LDRTL = new ScreenLayoutDir("ldrtl", 0x80);
public static final ScreenLayoutDir[] VALUES = new ScreenLayoutDir[]{
LDLTR,
LDRTL
};
private ScreenLayoutDir(String name, int flag) {
super(name, flag);
}
public static ScreenLayoutDir valueOf(int flag){
return Flag.valueOf(VALUES, MASK, flag);
}
public static ScreenLayoutDir valueOf(String name){
return Flag.valueOf(VALUES, name);
}
public static ScreenLayoutDir fromQualifiers(String qualifiers){
return Flag.fromQualifiers(VALUES, qualifiers);
}
public static ScreenLayoutDir fromQualifiers(String[] qualifiers){
return Flag.fromQualifiers(VALUES, qualifiers);
}
public static int update(ScreenLayoutDir flag, int value){
return Flag.update(MASK, flag, value);
}
}
public static final class ScreenLayoutRound extends Flag{
public static final int MASK = 0x03;
public static final ScreenLayoutRound NOTROUND = new ScreenLayoutRound("notround", 0x01);
public static final ScreenLayoutRound ROUND = new ScreenLayoutRound("round", 0x02);
public static final ScreenLayoutRound[] VALUES = new ScreenLayoutRound[]{
NOTROUND,
ROUND
};
private ScreenLayoutRound(String name, int flag) {
super(name, flag);
}
public static ScreenLayoutRound valueOf(int flag){
return Flag.valueOf(VALUES, MASK, flag);
}
public static ScreenLayoutRound valueOf(String name){
return Flag.valueOf(VALUES, name);
}
public static ScreenLayoutRound fromQualifiers(String qualifiers){
return Flag.fromQualifiers(VALUES, qualifiers);
}
public static ScreenLayoutRound fromQualifiers(String[] qualifiers){
return Flag.fromQualifiers(VALUES, qualifiers);
}
public static int update(ScreenLayoutRound flag, int value){
return Flag.update(MASK, flag, value);
}
}
public static final class ColorModeWide extends Flag{
public static final int MASK = 0x03;
public static final ColorModeWide NOWIDECG = new ColorModeWide("nowidecg", 0x01);
public static final ColorModeWide WIDECG = new ColorModeWide("widecg", 0x02);
public static final ColorModeWide[] VALUES = new ColorModeWide[]{
NOWIDECG,
WIDECG
};
private ColorModeWide(String name, int flag) {
super(name, flag);
}
public static ColorModeWide valueOf(int flag){
return Flag.valueOf(VALUES, MASK, flag);
}
public static ColorModeWide valueOf(String name){
return Flag.valueOf(VALUES, name);
}
public static ColorModeWide fromQualifiers(String qualifiers){
return Flag.fromQualifiers(VALUES, qualifiers);
}
public static ColorModeWide fromQualifiers(String[] qualifiers){
return Flag.fromQualifiers(VALUES, qualifiers);
}
public static int update(ColorModeWide flag, int value){
return Flag.update(MASK, flag, value);
}
}
public static final class ColorModeHdr extends Flag{
public static final int MASK = 0x0C;
public static final ColorModeHdr LOWDR = new ColorModeHdr("lowdr", 0x04);
public static final ColorModeHdr HIGHDR = new ColorModeHdr("highdr", 0x08);
public static final ColorModeHdr[] VALUES = new ColorModeHdr[]{
LOWDR,
HIGHDR
};
private ColorModeHdr(String name, int flag) {
super(name, flag);
}
public static ColorModeHdr valueOf(int flag){
return Flag.valueOf(VALUES, MASK, flag);
}
public static ColorModeHdr valueOf(String name){
return Flag.valueOf(VALUES, name);
}
public static ColorModeHdr fromQualifiers(String qualifiers){
return Flag.fromQualifiers(VALUES, qualifiers);
}
public static ColorModeHdr fromQualifiers(String[] qualifiers){
return Flag.fromQualifiers(VALUES, qualifiers);
}
public static int update(ColorModeHdr flag, int value){
return Flag.update(MASK, flag, value);
}
}
static class Flag{
private final String name;
private final int flag;
Flag(String name, int flag){
this.name = name;
this.flag = flag;
}
public int getFlag() {
return flag;
}
@Override
public boolean equals(Object obj) {
return obj == this;
}
@Override
public int hashCode() {
return super.hashCode();
}
@Override
public String toString() {
return name;
}
public static String toString(Flag flag){
if(flag!= null){
return flag.toString();
}
return null;
}
static T fromQualifiers(T[] values, String qualifiers){
if(qualifiers == null){
return null;
}
return fromQualifiers(values, qualifiers.split("\\s*-\\s*"));
}
static T fromQualifiers(T[] values, String[] qualifiers){
if(qualifiers == null){
return null;
}
for(int i = 0; i < qualifiers.length; i++){
T flag = Flag.valueOf(values, qualifiers[i]);
if(flag != null){
qualifiers[i] = null;
return flag;
}
}
return null;
}
static T valueOf(T[] values, int mask, int flagValue){
flagValue = flagValue & mask;
for(T flag:values){
if(flagValue == flag.getFlag()){
return flag;
}
}
return null;
}
static T valueOf(T[] values, String name){
if(name == null || name.length() == 0){
return null;
}
if(name.charAt(0) == '-'){
name = name.substring(1);
}
name = name.toLowerCase();
for(T flag:values){
if(name.equals(flag.toString())){
return flag;
}
}
return null;
}
public static int update(int mask, Flag flag, int value){
int flip = (~mask) & 0xff;
value = value & flip;
if(flag != null){
value = value | flag.getFlag();
}
return value;
}
}
static class QualifierBuilder{
private final ResConfig mConfig;
private StringBuilder mBuilder;
public QualifierBuilder(ResConfig resConfig){
this.mConfig = resConfig;
}
public String build(){
ResConfig resConfig = this.mConfig;
if(resConfig.isDefault()){
return "";
}
this.mBuilder = new StringBuilder();
appendPrefixedNumber("mcc", resConfig.getMcc());
appendPrefixedNumber("mnc", resConfig.getMnc());
appendLanguageAndRegion();
appendFlag(resConfig.getOrientation());
appendFlag(resConfig.getTouchscreen());
appendFlag(resConfig.getDensity());
appendFlag(resConfig.getKeyboard());
appendFlag(resConfig.getNavigation());
appendFlag(resConfig.getInputFlagsKeysHidden());
appendFlag(resConfig.getInputFlagsNavHidden());
appendScreenWidthHeight();
appendPrefixedNumber("v", resConfig.getSdkVersion());
// append resConfig.getMinorVersion()
appendFlag(resConfig.getScreenLayoutSize());
appendFlag(resConfig.getScreenLayoutLong());
appendFlag(resConfig.getScreenLayoutDir());
appendFlag(resConfig.getUiModeType());
appendFlag(resConfig.getUiModeNight());
appendDp("sw", resConfig.getSmallestScreenWidthDp());
appendDp("w", resConfig.getScreenWidthDp());
appendDp("h", resConfig.getScreenHeightDp());
appendFlag(resConfig.getScreenLayoutRound());
appendFlag(resConfig.getColorModeWide());
appendFlag(resConfig.getColorModeHdr());
appendLocaleNumberingSystem();
return mBuilder.toString();
}
private void appendScreenWidthHeight(){
ResConfig resConfig = this.mConfig;
int width = resConfig.getScreenWidth();
int height = resConfig.getScreenHeight();
if(width == 0 && height == 0){
return;
}
mBuilder.append('-').append(width).append('x').append(height);
}
private void appendLanguageAndRegion(){
ResConfig resConfig = this.mConfig;
String language = resConfig.getLanguage();
String region = resConfig.getRegion();
String script = resConfig.getLocaleScript();
String variant = resConfig.getLocaleVariant();
if(language == null && region == null){
return;
}
StringBuilder builder = this.mBuilder;
char separator;
if(script != null || variant != null){
builder.append('-');
builder.append('b');
separator = '+';
}else {
separator = '-';
}
if(language!= null){
builder.append(separator);
builder.append(language);
}
if(region!= null){
builder.append(separator);
if(region.length() == 2){
builder.append('r');
}
builder.append(region);
}
if(script!= null){
builder.append(separator);
builder.append(script);
}
if(variant!= null){
builder.append(separator);
builder.append(variant);
}
}
private void appendLocaleNumberingSystem(){
String numberingSystem = mConfig.getLocaleNumberingSystem();
if(numberingSystem== null){
return;
}
StringBuilder builder = mBuilder;
builder.append("-u+nu+");
builder.append(numberingSystem);
}
private void appendFlag(ResConfig.Flag flag){
if(flag== null){
return;
}
mBuilder.append('-').append(flag.toString());
}
private void appendDp(String prefix, int number){
if(number == 0){
return;
}
StringBuilder builder = this.mBuilder;
builder.append('-');
if(prefix!= null){
builder.append(prefix);
}
builder.append(number);
builder.append("dp");
}
private void appendPrefixedNumber(String prefix, int number){
if(number == 0){
return;
}
StringBuilder builder = this.mBuilder;
builder.append('-');
builder.append(prefix);
builder.append(number);
}
}
static class QualifierParser{
private final ResConfig mConfig;
private final String[] mQualifiers;
private final int mPreferredSize;
private boolean mEmpty;
private boolean mLanguageRegionParsed;
private boolean mParseComplete;
public QualifierParser(ResConfig resConfig, String[] qualifiers){
this.mConfig = resConfig;
this.mQualifiers = qualifiers;
this.mPreferredSize = resConfig.getConfigSize();
}
public QualifierParser(ResConfig resConfig, String qualifiers){
this(resConfig, splitQualifiers(qualifiers));
}
public void parse(){
if(this.mParseComplete){
return;
}
if(isEmpty()){
onParseComplete();
return;
}
ResConfig resConfig = this.mConfig;
resConfig.setConfigSize(ResConfig.SIZE_64);
parsePrefixedNumber();
parseDp();
parseWidthHeight();
parseLocaleNumberingSystem();
if(isEmpty()){
onParseComplete();
return;
}
String[] qualifiers = this.mQualifiers;
resConfig.setOrientation(ResConfig.Orientation.fromQualifiers(qualifiers));
resConfig.setTouchscreen(ResConfig.Touchscreen.fromQualifiers(qualifiers));
resConfig.setDensity(ResConfig.Density.fromQualifiers(qualifiers));
resConfig.setKeyboard(ResConfig.Keyboard.fromQualifiers(qualifiers));
resConfig.setNavigation(ResConfig.Navigation.fromQualifiers(qualifiers));
if(isEmpty()){
onParseComplete();
return;
}
resConfig.setInputFlagsKeysHidden(ResConfig.InputFlagsKeysHidden.fromQualifiers(qualifiers));
resConfig.setInputFlagsNavHidden(ResConfig.InputFlagsNavHidden.fromQualifiers(qualifiers));
resConfig.setScreenLayoutSize(ResConfig.ScreenLayoutSize.fromQualifiers(qualifiers));
resConfig.setScreenLayoutLong(ResConfig.ScreenLayoutLong.fromQualifiers(qualifiers));
resConfig.setScreenLayoutDir(ResConfig.ScreenLayoutDir.fromQualifiers(qualifiers));
if(isEmpty()){
onParseComplete();
return;
}
resConfig.setUiModeType(ResConfig.UiModeType.fromQualifiers(qualifiers));
resConfig.setUiModeNight(ResConfig.UiModeNight.fromQualifiers(qualifiers));
resConfig.setScreenLayoutRound(ResConfig.ScreenLayoutRound.fromQualifiers(qualifiers));
resConfig.setColorModeWide(ResConfig.ColorModeWide.fromQualifiers(qualifiers));
resConfig.setColorModeHdr(ResConfig.ColorModeHdr.fromQualifiers(qualifiers));
if(isEmpty()){
onParseComplete();
return;
}
parseLocaleScriptVariant();
parseLanguage();
parseRegion();
onParseComplete();
}
public String[] getErrors(){
if(!this.mParseComplete){
return null;
}
String[] qualifiers = this.mQualifiers;
if(qualifiers == null || qualifiers.length == 0){
return null;
}
int length = qualifiers.length;
String[] tmp = new String[length];
int count = 0;
for(int i = 0; i < length; i++){
String qualifier = qualifiers[i];
if(qualifier == null || qualifier.length() == 0){
continue;
}
tmp[count] = qualifier;
count++;
}
if(count == 0){
return null;
}
if(count == length){
return tmp;
}
String[] errors = new String[count];
System.arraycopy(tmp, 0, errors, 0, count);
return errors;
}
private void onParseComplete(){
this.mConfig.trimToSize(this.mPreferredSize);
this.mParseComplete = true;
}
private void parsePrefixedNumber(){
if(isEmpty()){
return;
}
String[] qualifiers = this.mQualifiers;
for(int i = 0; i < qualifiers.length; i++){
if(parsePrefixedNumber(qualifiers[i])){
qualifiers[i] = null;
}
}
}
private boolean parsePrefixedNumber(String qualifier){
if(qualifier == null){
return false;
}
Matcher matcher = PATTERN_PREFIX_NUMBER.matcher(qualifier);
if(!matcher.find()){
return false;
}
String prefix = matcher.group(1);
int value = Integer.parseInt(matcher.group(2));
ResConfig resConfig = mConfig;
if("mcc".equals(prefix)){
resConfig.setMcc(value);
}else if("mnc".equals(prefix)) {
resConfig.setMnc(value);
}else if("v".equals(prefix)){
resConfig.setSdkVersion(value);
}else {
return false;
}
return true;
}
private void parseDp(){
if(isEmpty()){
return;
}
String[] qualifiers = this.mQualifiers;
for(int i = 0; i < qualifiers.length; i++){
if(parseDp(qualifiers[i])){
qualifiers[i] = null;
}
}
}
private boolean parseDp(String qualifier){
if(qualifier == null){
return false;
}
Matcher matcher = PATTERN_DP.matcher(qualifier);
if(!matcher.find()){
return false;
}
String prefix = matcher.group(1);
int value = Integer.parseInt(matcher.group(2));
ResConfig resConfig = this.mConfig;
if("sw".equals(prefix)){
resConfig.setSmallestScreenWidthDp(value);
}else if("w".equals(prefix)) {
resConfig.setScreenWidthDp(value);
}else if("h".equals(prefix)){
resConfig.setScreenHeightDp(value);
}else {
return false;
}
return true;
}
private void parseWidthHeight(){
if(isEmpty()){
return;
}
String[] qualifiers = this.mQualifiers;
for(int i = 0; i < qualifiers.length; i++){
if(parseWidthHeight(qualifiers[i])){
qualifiers[i] = null;
return;
}
}
}
private boolean parseWidthHeight(String qualifier){
if(qualifier == null){
return false;
}
Matcher matcher = PATTERN_WIDTH_HEIGHT.matcher(qualifier);
if(!matcher.find()){
return false;
}
int width = Integer.parseInt(matcher.group(1));
int height = Integer.parseInt(matcher.group(2));
ResConfig resConfig = this.mConfig;
resConfig.setScreenWidth(width);
resConfig.setScreenHeight(height);
return true;
}
private void parseLocaleNumberingSystem(){
if(isEmpty()){
return;
}
String[] qualifiers = this.mQualifiers;
for(int i = 0; i < qualifiers.length; i++){
if(parseLocaleNumberingSystem(qualifiers[i])){
qualifiers[i] = null;
return;
}
}
}
private boolean parseLocaleNumberingSystem(String qualifier){
if(qualifier == null){
return false;
}
Matcher matcher = PATTERN_LOCALE_NUMBERING_SYSTEM.matcher(qualifier);
if(!matcher.find()){
return false;
}
this.mConfig.setLocaleNumberingSystem(matcher.group(1));
return true;
}
private void parseLocaleScriptVariant(){
if(this.mLanguageRegionParsed || isEmpty()){
return;
}
String[] qualifiers = this.mQualifiers;
for(int i = 0; i < qualifiers.length; i++){
if(parseLocaleScriptVariant(qualifiers[i])){
qualifiers[i] = null;
this.mLanguageRegionParsed = true;
return;
}
}
}
private boolean parseLocaleScriptVariant(String qualifier){
if(qualifier == null || qualifier.length() < 4 ){
return false;
}
char[] chars = qualifier.toCharArray();
if(chars[0] != 'b' || chars[1] != '+'){
return false;
}
Matcher matcher = PATTERN_LOCALE_SCRIPT_VARIANT.matcher(qualifier);
if(!matcher.find()){
return false;
}
String language = trimPlus(matcher.group(1));
String region = trimPlus(matcher.group(2));
String script = trimPlus(matcher.group(3));
String variant = trimPlus(matcher.group(4));
if(script == null && variant == null){
return false;
}
ResConfig resConfig = this.mConfig;
resConfig.setLanguage(language);
resConfig.setRegion(region);
resConfig.setLocaleScript(script);
resConfig.setLocaleVariant(variant);
return true;
}
private void parseLanguage(){
if(mLanguageRegionParsed || isEmpty()){
return;
}
String[] qualifiers = this.mQualifiers;
for(int i = 0; i < qualifiers.length; i++){
if(parseLanguage(qualifiers[i])){
qualifiers[i] = null;
return;
}
}
}
private boolean parseLanguage(String qualifier){
if(!isLanguage(qualifier)){
return false;
}
this.mConfig.setLanguage(qualifier);
return true;
}
private void parseRegion(){
if(mLanguageRegionParsed || isEmpty()){
return;
}
String[] qualifiers = this.mQualifiers;
for(int i = 0; i < qualifiers.length; i++){
if(parseRegion(qualifiers[i])){
qualifiers[i] = null;
return;
}
}
}
private boolean parseRegion(String qualifier){
if(!isRegion(qualifier)){
return false;
}
this.mConfig.setRegion(qualifier);
return true;
}
private boolean isEmpty(){
if(!mEmpty){
mEmpty = isEmpty(mQualifiers);
}
return mEmpty;
}
private static boolean isEmpty(String[] qualifiers){
if(qualifiers == null){
return true;
}
for(int i = 0; i < qualifiers.length; i++){
String qualifier = qualifiers[i];
if(qualifier == null){
continue;
}
if(qualifier.length() == 0){
qualifiers[i] = null;
continue;
}
return false;
}
return true;
}
private static String trimPlus(String text){
if(text == null||text.length() == 0){
return null;
}
if(text.charAt(0) == '+'){
text = text.substring(1);
}
return text;
}
private static boolean isLanguage(String qualifier){
if(qualifier == null){
return false;
}
char[] chars = qualifier.toCharArray();
int length = chars.length;
if(length != 2 && length !=3 ){
return false;
}
for(int i = 0; i < length; i++){
if(!isAtoZLower(chars[i])) {
return false;
}
}
return true;
}
private static boolean isRegion(String qualifier){
if(qualifier == null || qualifier.length() != 3){
return false;
}
char[] chars = qualifier.toCharArray();
boolean checkDigit = false;
for(int i = 0; i < chars.length; i++){
char ch = chars[i];
if(i == 0){
if(ch == 'r'){
continue;
}
checkDigit = isDigit(ch);
if(checkDigit){
continue;
}
return false;
}
if(checkDigit){
if(!isDigit(ch)){
return false;
}
}else if(!isAtoZUpper(ch)) {
return false;
}
}
return true;
}
private static String[] splitQualifiers(String qualifier){
if(qualifier == null || qualifier.length() == 0){
return null;
}
return qualifier.split("-");
}
private static boolean isDigit(char ch){
return ch <= '9' && ch >= '0';
}
private static boolean isAtoZLower(char ch){
return ch <= 'z' && ch >= 'a';
}
private static boolean isAtoZUpper(char ch){
return ch <= 'Z' && ch >= 'A';
}
private static final Pattern PATTERN_PREFIX_NUMBER = Pattern.compile("^([mcnv]+)([0-9]+)$");
private static final Pattern PATTERN_DP = Pattern.compile("^([swh]+)([0-9]+)dp$");
private static final Pattern PATTERN_WIDTH_HEIGHT = Pattern.compile("^([0-9]+)[xX]([0-9]+)$");
private static final Pattern PATTERN_LOCALE_NUMBERING_SYSTEM = Pattern.compile("^u\\+nu\\+(.{1,8})$");
private static final Pattern PATTERN_LOCALE_SCRIPT_VARIANT = Pattern.compile("^b(\\+[a-z]{2})?(\\+r[A-Z]{2})?(\\+[A-Z][a-z]{3})?(\\+[A-Z]{2,8})?$");
}
public static final int SIZE_16 = 16;
public static final int SIZE_28 = 28;
public static final int SIZE_32 = 32;
public static final int SIZE_36 = 36;
public static final int SIZE_48 = 48;
public static final int SIZE_52 = 52;
public static final int SIZE_56 = 56;
public static final int SIZE_64 = 64;
private static final int OFFSET_mcc = 0;
private static final int OFFSET_mnc = 2;
private static final int OFFSET_language = 4;
private static final int OFFSET_region = 6;
private static final int OFFSET_orientation = 8;
private static final int OFFSET_touchscreen = 9;
private static final int OFFSET_density = 10;
//SIZE=16
private static final int OFFSET_keyboard = 12;
private static final int OFFSET_navigation = 13;
private static final int OFFSET_inputFlags = 14;
private static final int OFFSET_inputPad0 = 15;
private static final int OFFSET_screenWidth = 16;
private static final int OFFSET_screenHeight = 18;
private static final int OFFSET_sdkVersion = 20;
private static final int OFFSET_minorVersion = 22;
//SIZE=28
private static final int OFFSET_screenLayout = 24;
private static final int OFFSET_uiMode = 25;
private static final int OFFSET_smallestScreenWidthDp = 26;
//SIZE=32
private static final int OFFSET_screenWidthDp = 28;
private static final int OFFSET_screenHeightDp = 30;
//SIZE=36
private static final int OFFSET_localeScript = 32;
private static final int OFFSET_localeVariant = 36;
//SIZE=48
private static final int OFFSET_screenLayout2 = 44;
private static final int OFFSET_colorMode = 45;
private static final int OFFSET_reservedPadding = 46;
//SIZE=52
private static final int OFFSET_localeNumberingSystem = 48;
//SIZE=60
private static final int LEN_localeScript = 4;
private static final int LEN_localeVariant = 8;
private static final int LEN_localeNumberingSystem = 8;
private static final String NAME_mcc = "mcc";
private static final String NAME_mnc = "mnc";
private static final String NAME_language = "language";
private static final String NAME_region = "region";
private static final String NAME_orientation = "orientation";
private static final String NAME_touchscreen = "touchscreen";
private static final String NAME_density = "density";
//SIZE=16
private static final String NAME_keyboard = "keyboard";
private static final String NAME_navigation = "navigation";
private static final String NAME_input_flags_keys_hidden = "input_flags_keys_hidden";
private static final String NAME_input_flags_nav_hidden = "input_flags_nav_hidden";
private static final String NAME_inputPad0 = "inputPad0";
private static final String NAME_screenWidth = "screenWidth";
private static final String NAME_screenHeight = "screenHeight";
private static final String NAME_sdkVersion = "sdkVersion";
private static final String NAME_minorVersion = "minorVersion";
//SIZE=28
private static final String NAME_screen_layout_size = "screen_layout_size";
private static final String NAME_screen_layout_long = "screen_layout_long";
private static final String NAME_screen_layout_dir = "screen_layout_dir";
private static final String NAME_ui_mode_type = "ui_mode_type";
private static final String NAME_ui_mode_night = "ui_mode_night";
private static final String NAME_smallestScreenWidthDp = "smallestScreenWidthDp";
//SIZE=32 = "";
private static final String NAME_screenWidthDp = "screenWidthDp";
private static final String NAME_screenHeightDp = "screenHeightDp";
//SIZE=36
private static final String NAME_localeScript = "localeScript";
private static final String NAME_localeVariant = "localeVariant";
private static final String NAME_screen_layout_round = "screen_layout_round";
private static final String NAME_color_mode_wide = "color_mode_wide";
private static final String NAME_color_mode_hdr = "color_mode_hdr";
private static final String NAME_localeNumberingSystem = "localeNumberingSystem";
private static final char POSTFIX_locale = '#';
private static final ResConfig DEFAULT_INSTANCE = new ResConfig(SIZE_16);
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy