create new qualifier parser for ResConfig

This commit is contained in:
REAndroid 2023-03-25 12:01:52 -04:00
parent ce4621d026
commit a92e929812
2 changed files with 433 additions and 569 deletions

View File

@ -26,6 +26,8 @@
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<JSONObject>, Comparable<ResConfig> {
@ -66,8 +68,13 @@
@Override
protected void onRefreshed() {
}
public void parseQualifiers(String name){
ResConfigHelper.parseQualifiers(this, name);
/**
* returns null if parsing is ok, else returns unknown qualifiers
* */
public String[] parseQualifiers(String qualifiers){
QualifierParser parser = new QualifierParser(this, qualifiers);
parser.parse();
return parser.getErrors();
}
public void setConfigSize(int size){
if(!isValidSize(size)){
@ -102,14 +109,14 @@
return true;
}
public void setMcc(short sh){
public void setMcc(int value){
if(getConfigSize()<SIZE_16){
if(sh==0){
if(value==0){
return;
}
throw new IllegalArgumentException("Can not set mcc for config size="+getConfigSize());
}
mValuesContainer.putShort(OFFSET_mcc, sh);
mValuesContainer.putShort(OFFSET_mcc, value);
}
public int getMcc(){
if(getConfigSize()<SIZE_16){
@ -117,14 +124,14 @@
}
return mValuesContainer.getShortUnsigned(OFFSET_mcc);
}
public void setMnc(short sh){
public void setMnc(int value){
if(getConfigSize()<SIZE_16){
if(sh==0){
if(value==0){
return;
}
throw new IllegalArgumentException("Can not set mnc for config size="+getConfigSize());
}
mValuesContainer.putShort(OFFSET_mnc, sh);
mValuesContainer.putShort(OFFSET_mnc, value);
}
public int getMnc(){
if(getConfigSize()<SIZE_16){
@ -195,6 +202,9 @@
public void setRegion(String region){
char[] chars = null;
if(region!=null){
if(region.length()==3 && region.charAt(0) == 'r'){
region = region.substring(1);
}
chars = region.toCharArray();
}
setRegion(chars);
@ -213,7 +223,7 @@
}
throw new IllegalArgumentException("Can not set orientation for config size="+getConfigSize());
}
mValuesContainer.put(OFFSET_orientation, (byte) orientation);
mValuesContainer.putByte(OFFSET_orientation, orientation);
}
public int getOrientationValue(){
if(getConfigSize()<SIZE_16){
@ -234,7 +244,7 @@
}
throw new IllegalArgumentException("Can not set touchscreen for config size="+getConfigSize());
}
mValuesContainer.put(OFFSET_touchscreen, (byte) touchscreen);
mValuesContainer.putByte(OFFSET_touchscreen, touchscreen);
}
public int getTouchscreenValue(){
if(getConfigSize()<SIZE_16){
@ -255,7 +265,7 @@
}
throw new IllegalArgumentException("Can not set density for config size="+getConfigSize());
}
mValuesContainer.putShort(OFFSET_density, (short) density);
mValuesContainer.putShort(OFFSET_density, density);
}
public int getDensityValue(){
if(getConfigSize()<SIZE_16){
@ -276,7 +286,7 @@
}
throw new IllegalArgumentException("Can not set keyboard for config size="+getConfigSize());
}
mValuesContainer.put(OFFSET_keyboard, (byte) keyboard);
mValuesContainer.putByte(OFFSET_keyboard, keyboard);
}
public int getKeyboardValue(){
if(getConfigSize()<SIZE_28){
@ -297,7 +307,7 @@
}
throw new IllegalArgumentException("Can not set navigation for config size="+getConfigSize());
}
mValuesContainer.put(OFFSET_navigation, (byte) navigation);
mValuesContainer.putByte(OFFSET_navigation, navigation);
}
public int getNavigationValue(){
if(getConfigSize()<SIZE_28){
@ -318,7 +328,7 @@
}
throw new IllegalArgumentException("Can not set inputFlags for config size="+getConfigSize());
}
mValuesContainer.put(OFFSET_inputFlags, (byte) inputFlags);
mValuesContainer.putByte(OFFSET_inputFlags, inputFlags);
}
public int getInputFlagsValue(){
if(getConfigSize()<SIZE_28){
@ -353,14 +363,14 @@
}
return mValuesContainer.get(OFFSET_inputPad0);
}
public void setScreenWidth(short sh){
public void setScreenWidth(int value){
if(getConfigSize()<SIZE_28){
if(sh==0){
if(value==0){
return;
}
throw new IllegalArgumentException("Can not set screenWidth for config size="+getConfigSize());
}
mValuesContainer.putShort(OFFSET_screenWidth, sh);
mValuesContainer.putShort(OFFSET_screenWidth, value);
}
public int getScreenWidth(){
if(getConfigSize()<SIZE_28){
@ -368,14 +378,14 @@
}
return mValuesContainer.getShortUnsigned(OFFSET_screenWidth);
}
public void setScreenHeight(short sh){
public void setScreenHeight(int value){
if(getConfigSize()<SIZE_28){
if(sh==0){
if(value==0){
return;
}
throw new IllegalArgumentException("Can not set screenHeight for config size="+getConfigSize());
}
mValuesContainer.putShort(OFFSET_screenHeight, sh);
mValuesContainer.putShort(OFFSET_screenHeight, value);
}
public int getScreenHeight(){
if(getConfigSize()<SIZE_28){
@ -383,18 +393,18 @@
}
return mValuesContainer.getShortUnsigned(OFFSET_screenHeight);
}
public void setScreenSize(short w, short h){
this.setScreenWidth(w);
this.setScreenHeight(h);
public void setScreenSize(int width, int height){
this.setScreenWidth(width);
this.setScreenHeight(height);
}
public void setSdkVersion(short sh){
public void setSdkVersion(int value){
if(getConfigSize()<SIZE_28){
if(sh==0){
if(value==0){
return;
}
throw new IllegalArgumentException("Can not set sdkVersion for config size="+getConfigSize());
}
mValuesContainer.putShort(OFFSET_sdkVersion, sh);
mValuesContainer.putShort(OFFSET_sdkVersion, value);
}
public int getSdkVersion(){
if(getConfigSize()<SIZE_28){
@ -402,14 +412,14 @@
}
return mValuesContainer.getShortUnsigned(OFFSET_sdkVersion);
}
public void setMinorVersion(short sh){
public void setMinorVersion(int value){
if(getConfigSize()<SIZE_28){
if(sh==0){
if(value==0){
return;
}
throw new IllegalArgumentException("Can not set minorVersion for config size="+getConfigSize());
}
mValuesContainer.putShort(OFFSET_minorVersion, sh);
mValuesContainer.putShort(OFFSET_minorVersion, value);
}
public int getMinorVersion(){
if(getConfigSize()<SIZE_28){
@ -424,7 +434,7 @@
}
throw new IllegalArgumentException("Can not set screenLayout for config size="+getConfigSize());
}
mValuesContainer.put(OFFSET_screenLayout, (byte) layout);
mValuesContainer.putByte(OFFSET_screenLayout, layout);
}
public int getScreenLayout(){
if(getConfigSize()<SIZE_32){
@ -457,7 +467,7 @@
}
throw new IllegalArgumentException("Can not set uiMode for config size="+getConfigSize());
}
mValuesContainer.put(OFFSET_uiMode, (byte) mode);
mValuesContainer.putByte(OFFSET_uiMode, mode);
}
public int getUiMode(){
if(getConfigSize()<SIZE_32){
@ -477,14 +487,14 @@
public void setUiModeNight(UiModeNight uiModeNight){
setUiMode(UiModeNight.update(uiModeNight, getUiMode()));
}
public void setSmallestScreenWidthDp(short sh){
public void setSmallestScreenWidthDp(int value){
if(getConfigSize()<SIZE_32){
if(sh==0){
if(value==0){
return;
}
throw new IllegalArgumentException("Can not set smallestScreenWidthDp for config size="+getConfigSize());
}
mValuesContainer.putShort(OFFSET_smallestScreenWidthDp, sh);
mValuesContainer.putShort(OFFSET_smallestScreenWidthDp, value);
}
public int getSmallestScreenWidthDp(){
if(getConfigSize()<SIZE_32){
@ -492,14 +502,14 @@
}
return mValuesContainer.getShortUnsigned(OFFSET_smallestScreenWidthDp);
}
public void setScreenWidthDp(short sh){
public void setScreenWidthDp(int value){
if(getConfigSize()<SIZE_36){
if(sh==0){
if(value==0){
return;
}
throw new IllegalArgumentException("Can not set screenWidthDp for config size="+getConfigSize());
}
mValuesContainer.putShort(OFFSET_screenWidthDp, sh);
mValuesContainer.putShort(OFFSET_screenWidthDp, value);
}
public int getScreenWidthDp(){
if(getConfigSize()<SIZE_36){
@ -507,14 +517,14 @@
}
return mValuesContainer.getShortUnsigned(OFFSET_screenWidthDp);
}
public void setScreenHeightDp(short sh){
public void setScreenHeightDp(int value){
if(getConfigSize()<SIZE_36){
if(sh==0){
if(value==0){
return;
}
throw new IllegalArgumentException("Can not set screenHeightDp for config size="+getConfigSize());
}
mValuesContainer.putShort(OFFSET_screenHeightDp, sh);
mValuesContainer.putShort(OFFSET_screenHeightDp, value);
}
public int getScreenHeightDp(){
if(getConfigSize()<SIZE_36){
@ -623,7 +633,7 @@
}
throw new IllegalArgumentException("Can not set screenLayout2 for config size="+getConfigSize());
}
mValuesContainer.put(OFFSET_screenLayout2, (byte) screenLayout2);
mValuesContainer.putByte(OFFSET_screenLayout2, screenLayout2);
}
public int getScreenLayout2(){
if(getConfigSize()<SIZE_52){
@ -644,7 +654,7 @@
}
throw new IllegalArgumentException("Can not set colorMode for config size="+getConfigSize());
}
mValuesContainer.put(OFFSET_colorMode, (byte) colorMode);
mValuesContainer.putByte(OFFSET_colorMode, colorMode);
}
public int getColorMode(){
if(getConfigSize()<SIZE_56){
@ -710,14 +720,7 @@
}
public boolean isEqualQualifiers(String qualifiers){
if(qualifiers==null){
qualifiers="";
}
qualifiers=ResConfigHelper.sortQualifiers(qualifiers);
return getQualifiers().equals(qualifiers);
}
public String getLocale(){
return ResConfigHelper.decodeLocale(this);
return this.equals(parse(qualifiers));
}
public boolean isDefault(){
return isNull(mValuesContainer.getBytes());
@ -809,8 +812,8 @@
}
trimToSize(SIZE_64);
setMcc((short) json.optInt(NAME_mcc));
setMnc((short) json.optInt(NAME_mnc));
setMcc(json.optInt(NAME_mcc));
setMnc(json.optInt(NAME_mnc));
setLanguage(json.optString(NAME_language));
setRegion(json.optString(NAME_region));
setOrientation(Orientation.valueOf(json.optString(NAME_orientation)));
@ -820,18 +823,18 @@
setNavigation(Navigation.valueOf(json.optString(NAME_navigation)));
setInputFlagsKeysHidden(InputFlagsKeysHidden.valueOf(json.optString(NAME_input_flags_keys_hidden)));
setInputFlagsNavHidden(InputFlagsNavHidden.valueOf(json.optString(NAME_input_flags_nav_hidden)));
setScreenWidth((short) json.optInt(NAME_screenWidth));
setScreenHeight((short) json.optInt(NAME_screenHeight));
setSdkVersion((short) json.optInt(NAME_sdkVersion));
setMinorVersion((short) json.optInt(NAME_minorVersion));
setScreenWidth(json.optInt(NAME_screenWidth));
setScreenHeight(json.optInt(NAME_screenHeight));
setSdkVersion(json.optInt(NAME_sdkVersion));
setMinorVersion(json.optInt(NAME_minorVersion));
setScreenLayoutSize(ScreenLayoutSize.valueOf(json.optString(NAME_screen_layout_size)));
setScreenLayoutLong(ScreenLayoutLong.valueOf(json.optString(NAME_screen_layout_long)));
setScreenLayoutDir(ScreenLayoutDir.valueOf(json.optString(NAME_screen_layout_dir)));
setUiModeType(UiModeType.valueOf(json.optString(NAME_ui_mode_type)));
setUiModeNight(UiModeNight.valueOf(json.optString(NAME_ui_mode_night)));
setSmallestScreenWidthDp((short) json.optInt(NAME_smallestScreenWidthDp));
setScreenWidthDp((short) json.optInt(NAME_screenWidthDp));
setScreenHeightDp((short) json.optInt(NAME_screenHeightDp));
setSmallestScreenWidthDp(json.optInt(NAME_smallestScreenWidthDp));
setScreenWidthDp(json.optInt(NAME_screenWidthDp));
setScreenHeightDp(json.optInt(NAME_screenHeightDp));
setLocaleScript(json.optString(NAME_localeScript));
setLocaleVariantInternal(json.optString(NAME_localeVariant));
setScreenLayoutRound(ScreenLayoutRound.valueOf(json.optString(NAME_screen_layout_round)));
@ -874,6 +877,12 @@
return getQualifiers().compareTo(resConfig.getQualifiers());
}
public static ResConfig parse(String qualifiers){
ResConfig resConfig = new ResConfig();
resConfig.parseQualifiers(qualifiers);
return resConfig;
}
private static char[] unPackLanguage(byte in0, byte in1) {
return unpackLanguageOrRegion(in0, in1, 'a');
@ -1192,7 +1201,7 @@
public static final int MASK = 0x0f;
public static final Keyboard NOKEYS = new Keyboard("nokeys", 0x01);
public static final Keyboard QWERTY = new Keyboard("nokeys", 0x02);
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[]{
@ -1361,10 +1370,10 @@
}
public static final class UiModeNight extends Flag{
public static final int MASK = 0x30;
public static final UiModeNight NONIGHT = new UiModeNight("nonight",0x10);
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[]{
NONIGHT,
NOTNIGHT,
NIGHT
};
private UiModeNight(String name, int flag) {
@ -1474,10 +1483,10 @@
}
public static final class ScreenLayoutRound extends Flag{
public static final int MASK = 0x03;
public static final ScreenLayoutRound NOROUND = new ScreenLayoutRound("noround", 0x01);
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[]{
NOROUND,
NOTROUND,
ROUND
};
private ScreenLayoutRound(String name, int flag) {
@ -1592,9 +1601,10 @@
if(qualifiers == null){
return null;
}
for(String name:qualifiers){
T flag = Flag.valueOf(values, name);
for(int i=0;i < qualifiers.length;i++){
T flag = Flag.valueOf(values, qualifiers[i]);
if(flag != null){
qualifiers[i] = null;
return flag;
}
}
@ -1646,8 +1656,8 @@
return "";
}
this.mBuilder = new StringBuilder();
appendNumber("mcc", resConfig.getMcc());
appendNumber("mnc", resConfig.getMnc());
appendPrefixedNumber("mcc", resConfig.getMcc());
appendPrefixedNumber("mnc", resConfig.getMnc());
appendLanguageAndRegion();
@ -1661,7 +1671,7 @@
appendScreenWidthHeight();
appendNumber("v", resConfig.getSdkVersion());
appendPrefixedNumber("v", resConfig.getSdkVersion());
// append resConfig.getMinorVersion()
appendFlag(resConfig.getScreenLayoutSize());
appendFlag(resConfig.getScreenLayoutLong());
@ -1704,6 +1714,7 @@
StringBuilder builder = this.mBuilder;
char separator;
if(script != null || variant != null){
builder.append('-');
builder.append('b');
separator = '+';
}else {
@ -1756,18 +1767,367 @@
builder.append(number);
builder.append("dp");
}
private void appendNumber(String prefix, int number){
private void appendPrefixedNumber(String prefix, int number){
if(number == 0){
return;
}
StringBuilder builder = this.mBuilder;
builder.append('-');
if(prefix!=null){
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){
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(qualifier==null){
return false;
}
Matcher matcher = PATTERN_LANGUAGE.matcher(qualifier);
if(!matcher.matches()){
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(qualifier==null){
return false;
}
Matcher matcher = PATTERN_REGION.matcher(qualifier);
if(!matcher.matches()){
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 String[] splitQualifiers(String qualifier){
if(qualifier==null || qualifier.length()==0){
return null;
}
return qualifier.split("-");
}
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})?$");
private static final Pattern PATTERN_LANGUAGE = Pattern.compile("^[a-z]{2}$");
private static final Pattern PATTERN_REGION = Pattern.compile("^r[A-Z]{2}$");
}
public static final int SIZE_16 = 16;
public static final int SIZE_28 = 28;

View File

@ -1,496 +0,0 @@
/*
* 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 java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ResConfigHelper {
public static ResConfig fromQualifiers(String qualifiers){
ResConfig result=new ResConfig();
result.setConfigSize(ResConfig.SIZE_64);
parseQualifiers(result, qualifiers);
result.refresh();
return result;
}
static void parseQualifiers(ResConfig resConfig, String name){
if(resConfig == null || name==null){
return;
}
String[] split=name.split("-");
if(isNull(split)){
return;
}
encode(resConfig, split);
}
public static String sortQualifiers(String qualifiers){
if(!qualifiers.startsWith("-")){
return qualifiers;
}
String[] split=qualifiers.split("-");
if(isNull(split)){
return qualifiers;
}
List<String> qList=new ArrayList<>();
for(int i=0;i<split.length;i++){
String q=split[i];
if(q!=null && !qList.contains(q)){
qList.add(q);
}
}
Comparator<String> cmp=new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.compareTo(s2);
}
};
qList.sort(cmp);
StringBuilder builder=new StringBuilder();
for(String q:qList){
builder.append('-');
builder.append(q);
}
return builder.toString();
}
private static void encode(ResConfig resConfig, String[] split){
encodeDensity(resConfig, split);
encodeScreenHeightDp(resConfig, split);
encodeScreenWidthDp(resConfig, split);
encodeSmallestScreenWidthDp(resConfig, split);
encodeNavigation(resConfig, split);
encodeInputFlags(resConfig, split);
encodeSdkVersion(resConfig, split);
encodeKeyboard(resConfig, split);
encodeTouchscreen(resConfig, split);
encodeUiMode(resConfig, split);
encodeOrientation(resConfig, split);
encodeScreenLayout(resConfig, split);
encodeScreenLayout2(resConfig, split);
encodeColorMode(resConfig, split);
encodeMcc(resConfig, split);
encodeMnc(resConfig, split);
encodeScreenSize(resConfig, split);
encodeLanguageAndCountry(resConfig, split);
encodeScriptAndVariant(resConfig, split);
}
private static void encodeLanguageAndCountry(ResConfig resConfig, String[] split){
if(split==null){
return;
}
String lang=null;
String country=null;
for(int i=0;i<split.length;i++){
String s=split[i];
if(s==null){
continue;
}
if(lang==null){
if(isLanguageName(s)){
lang=s;
split[i]=null;
}else if(isCountryName(s)){
country=s;
split[i]=null;
}
continue;
}
if(country!=null){
break;
}
if(isCountryName(s)){
country=s;
split[i]=null;
break;
}
break;
}
if(lang!=null){
char[] chs=lang.toCharArray();
resConfig.setLanguage(chs);
}
if(country==null){
return;
}
if(country.length()>2 && country.startsWith("r")){
country=country.substring(1);
}
char[] chs=country.toCharArray();
resConfig.setRegion(chs);
}
private static void encodeScriptAndVariant(ResConfig resConfig, String[] split){
if(split==null){
return;
}
for(int i=0;i<split.length;i++){
String s=split[i];
if(encodeScriptAndVariant(resConfig, s)){
split[i] = null;
break;
}
}
}
private static boolean encodeScriptAndVariant(ResConfig resConfig, String str){
if(str==null){
return false;
}
if(!str.startsWith("b+")){
return false;
}
str = str.substring(2);
String[] splits = str.split("\\+");
String lang = null;
String region = null;
String script = null;
String variant = null;
for(int i=0; i<splits.length; i++){
String s = splits[i];
int len = s.length();
if(len==0){
continue;
}
if(isLocaleVariant(s)){
if(variant!=null){
return false;
}
variant = s;
continue;
}
if(isLanguageName(s)){
if(lang!=null){
return false;
}
lang = s;
continue;
}
boolean is_region = (region==null && isCountryName(s));
boolean is_script = (script==null && isLocaleScript(s));
if(is_region && is_script){
if(s.charAt(len-1)=='#'){
script = s;
continue;
}
if(len==3 && s.charAt(0)=='r'){
region = s;
continue;
}
// TODO: should throw error or false ?
return false;
}
if(is_region){
region = s;
continue;
}
if(is_script){
script = s;
continue;
}
// TODO: should throw error or false ?
return false;
}
if(lang!=null){
resConfig.setLanguage(lang);
}
if(region!=null){
if(region.charAt(0)=='r'){
region = region.substring(1);
}
resConfig.setRegion(region);
}
if(script!=null){
resConfig.setLocaleScript(script);
}
if(variant!=null){
resConfig.setLocaleVariant(variant);
}
return true;
}
public static String decodeLocale(ResConfig resConfig){
String region = resConfig.getRegion();
String language = resConfig.getLanguage();
StringBuilder builder=new StringBuilder();
if(language!=null){
builder.append(language);
}
if(region!=null){
if(language!=null){
builder.append('-');
}
builder.append(region);
}
if(builder.length()==0){
return null;
}
return builder.toString();
}
private static void encodeNavigation(ResConfig resConfig, String[] split){
resConfig.setNavigation(ResConfig.Navigation.fromQualifiers(split));
}
private static void encodeInputFlags(ResConfig resConfig, String[] split){
resConfig.setInputFlagsKeysHidden(ResConfig.InputFlagsKeysHidden.fromQualifiers(split));
resConfig.setInputFlagsNavHidden(ResConfig.InputFlagsNavHidden.fromQualifiers(split));
}
private static void encodeKeyboard(ResConfig resConfig, String[] split){
resConfig.setKeyboard(ResConfig.Keyboard.fromQualifiers(split));
}
private static void encodeDensity(ResConfig resConfig, String[] split){
resConfig.setDensity(ResConfig.Density.fromQualifiers(split));
}
private static void encodeTouchscreen(ResConfig resConfig, String[] split){
resConfig.setTouchscreen(ResConfig.Touchscreen.fromQualifiers(split));
}
private static void encodeUiMode(ResConfig resConfig, String[] split){
resConfig.setUiModeNight(ResConfig.UiModeNight.fromQualifiers(split));
resConfig.setUiModeType(ResConfig.UiModeType.fromQualifiers(split));
}
private static void encodeOrientation(ResConfig resConfig, String[] split){
resConfig.setOrientation(ResConfig.Orientation.fromQualifiers(split));
}
private static void encodeScreenLayout(ResConfig resConfig, String[] split){
resConfig.setScreenLayoutSize(ResConfig.ScreenLayoutSize.fromQualifiers(split));
resConfig.setScreenLayoutLong(ResConfig.ScreenLayoutLong.fromQualifiers(split));
resConfig.setScreenLayoutDir(ResConfig.ScreenLayoutDir.fromQualifiers(split));
}
private static void encodeScreenLayout2(ResConfig resConfig, String[] split){
resConfig.setScreenLayoutRound(ResConfig.ScreenLayoutRound.fromQualifiers(split));
}
private static void encodeColorMode(ResConfig resConfig, String[] split){
resConfig.setColorModeWide(ResConfig.ColorModeWide.fromQualifiers(split));
resConfig.setColorModeHdr(ResConfig.ColorModeHdr.fromQualifiers(split));
}
private static void encodeMcc(ResConfig resConfig, String[] split){
short sh=(short)0;
for(int i=0;i<split.length;i++){
String s=split[i];
if(s==null){
continue;
}
Matcher matcher=PATTERN_MCC_MNC.matcher(s);
if(!matcher.find()){
continue;
}
String mccMnc=matcher.group(1);
int val=Integer.parseInt(matcher.group(2));
if(val==0){
val=-1;
}
sh=(short)val;
if(!"mcc".equals(mccMnc)){
continue;
}
split[i]=null;
break;
}
resConfig.setMcc(sh);
}
private static void encodeMnc(ResConfig resConfig, String[] split){
short sh=(short)0;
for(int i=0;i<split.length;i++){
String s=split[i];
if(s==null){
continue;
}
Matcher matcher=PATTERN_MCC_MNC.matcher(s);
if(!matcher.find()){
continue;
}
String mccMnc=matcher.group(1);
int val=Integer.parseInt(matcher.group(2));
sh=(short)val;
if(!"mnc".equals(mccMnc)){
continue;
}
split[i]=null;
break;
}
resConfig.setMnc(sh);
}
private static void encodeSmallestScreenWidthDp(ResConfig resConfig, String[] split){
int val=0;
for(int i=0;i<split.length;i++){
String s=split[i];
if(s==null){
continue;
}
Matcher matcher=PATTERN_SCREEN_SMALLEST_DP.matcher(s);
if(!matcher.find()){
continue;
}
val=Integer.parseInt(matcher.group(1));
split[i]=null;
break;
}
resConfig.setSmallestScreenWidthDp((short)val);
}
private static void encodeScreenHeightDp(ResConfig resConfig, String[] split){
int val=0;
for(int i=0;i<split.length;i++){
String s=split[i];
if(s==null){
continue;
}
Matcher matcher=PATTERN_SCREEN_DP.matcher(s);
if(!matcher.find()){
continue;
}
String pre=matcher.group(1);
if(!pre.equals("h")){
continue;
}
val=Integer.parseInt(matcher.group(2));
split[i]=null;
break;
}
resConfig.setScreenHeightDp((short)val);
}
private static void encodeScreenWidthDp(ResConfig resConfig, String[] split){
int val=0;
for(int i=0;i<split.length;i++){
String s=split[i];
if(s==null){
continue;
}
Matcher matcher=PATTERN_SCREEN_DP.matcher(s);
if(!matcher.find()){
continue;
}
String pre=matcher.group(1);
if(!pre.equals("w")){
continue;
}
val=Integer.parseInt(matcher.group(2));
split[i]=null;
break;
}
resConfig.setScreenWidthDp((short)val);
}
private static void encodeSdkVersion(ResConfig resConfig, String[] split){
int val=0;
for(int i=0;i<split.length;i++){
String s=split[i];
if(s==null){
continue;
}
Matcher matcher=PATTERN_SDK_VERSION.matcher(s);
if(!matcher.find()){
continue;
}
val=Integer.parseInt(matcher.group(1));
split[i]=null;
break;
}
resConfig.setSdkVersion((short)val);
}
private static void encodeScreenSize(ResConfig resConfig, String[] split){
for(int i=0;i<split.length;i++){
String s=split[i];
if(s==null){
continue;
}
Matcher matcher=PATTERN_SCREEN_SIZE.matcher(s);
if(!matcher.find()){
continue;
}
int a=Integer.parseInt(matcher.group(1));
int b=Integer.parseInt(matcher.group(2));
short w;
short h;
if(a>b){
w=(short)a;
h=(short)b;
}else {
w=(short)b;
h=(short)a;
}
resConfig.setScreenSize(w, h);
split[i]=null;
break;
}
}
private static boolean isLanguageName(String str){
if(str==null){
return false;
}
Matcher matcher=PATTERN_LANG_NAME.matcher(str);
return matcher.find();
}
private static boolean isLocaleScript(String str){
if(str==null){
return false;
}
Matcher matcher=PATTERN_LOCALE_SCRIPT.matcher(str);
return matcher.find();
}
private static boolean isLocaleVariant(String str){
if(str==null){
return false;
}
Matcher matcher=PATTERN_LOCALE_VARIANT.matcher(str);
return matcher.find();
}
private static boolean isCountryName(String str){
if(str==null){
return false;
}
Matcher matcher=PATTERN_COUNTRY_NAME.matcher(str);
return matcher.find();
}
private static boolean isNull(String[] split){
if(split==null){
return true;
}
if(split.length==0){
return true;
}
boolean result=true;
for(int i=0;i<split.length;i++){
String s=split[i];
if(s==null){
continue;
}
s=s.trim();
if(s.length()==0){
split[i]=null;
continue;
}
result=false;
}
return result;
}
private static final Pattern PATTERN_SDK_VERSION=Pattern.compile("^-?v([0-9]+)$");
private static final Pattern PATTERN_SCREEN_DP=Pattern.compile("^([wh])([0-9]+)dp$");
private static final Pattern PATTERN_SCREEN_SMALLEST_DP=Pattern.compile("^sw([0-9]+)dp$");
private static final Pattern PATTERN_LANG_NAME=Pattern.compile("^[a-z]{2}$");
private static final Pattern PATTERN_COUNTRY_NAME=Pattern.compile("^[a-zA-Z]{2,3}$");
private static final Pattern PATTERN_LOCALE_SCRIPT=Pattern.compile("^[a-zA-Z0-9]{3,4}$");
private static final Pattern PATTERN_LOCALE_VARIANT=Pattern.compile("^[a-zA-Z0-9#]{5,8}$");
private static final Pattern PATTERN_MCC_MNC=Pattern.compile("^(m[cn]c)([0-9]{2,3})$");
private static final Pattern PATTERN_SCREEN_SIZE=Pattern.compile("^-?([0-9]+)x([0-9]+)$");
}