mirror of
https://github.com/revanced/ARSCLib.git
synced 2025-05-08 09:44:26 +02:00
2271 lines
84 KiB
Java
Executable File
2271 lines
84 KiB
Java
Executable File
/*
|
|
* 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<JSONObject>, Comparable<ResConfig> {
|
|
|
|
private final IntegerItem configSize;
|
|
private final ByteArray mValuesContainer;
|
|
|
|
private String mQualifiers;
|
|
private int mQualifiersStamp;
|
|
|
|
public ResConfig(){
|
|
super(2);
|
|
this.configSize = new IntegerItem(SIZE_64);
|
|
this.mValuesContainer = new ByteArray(SIZE_64 - 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<max; i++){
|
|
byte other = otherBytes[i];
|
|
if(other == 0){
|
|
continue;
|
|
}
|
|
if(bytes[i] != other){
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
public void copyFrom(ResConfig resConfig){
|
|
if(resConfig==this||resConfig==null){
|
|
return;
|
|
}
|
|
setConfigSize(resConfig.getConfigSize());
|
|
mValuesContainer.putByteArray(0, resConfig.mValuesContainer.toArray());
|
|
}
|
|
@Override
|
|
public void onBlockLoaded(BlockReader reader, Block sender) throws IOException {
|
|
if(sender==configSize){
|
|
setConfigSize(configSize.get());
|
|
}
|
|
}
|
|
@Override
|
|
protected void onPreRefreshRefresh(){
|
|
int count=countBytes();
|
|
configSize.set(count);
|
|
}
|
|
@Override
|
|
protected void onRefreshed() {
|
|
}
|
|
/**
|
|
* 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)){
|
|
throw new IllegalArgumentException("Invalid config size = " + size);
|
|
}
|
|
this.configSize.set(size);
|
|
size=size-4;
|
|
mValuesContainer.setSize(size);
|
|
}
|
|
public int getConfigSize(){
|
|
return this.configSize.get();
|
|
}
|
|
public boolean trimToSize(int size){
|
|
int current=getConfigSize();
|
|
if(current==size){
|
|
return true;
|
|
}
|
|
if(!isValidSize(size)){
|
|
return false;
|
|
}
|
|
if(current<size){
|
|
setConfigSize(size);
|
|
return true;
|
|
}
|
|
int offset=size-4;
|
|
int len=current-4-offset;
|
|
byte[] bts=mValuesContainer.getByteArray(offset, len);
|
|
if(!isNull(bts)){
|
|
return false;
|
|
}
|
|
setConfigSize(size);
|
|
return true;
|
|
}
|
|
public void trimToMinimumSize(){
|
|
int size = ByteArray.trimTrailZeros(mValuesContainer.getBytes()).length + 4;
|
|
size = nearestSize(size);
|
|
trimToSize(size);
|
|
}
|
|
|
|
public void setMcc(int value){
|
|
if(getConfigSize()<SIZE_16){
|
|
if(value==0){
|
|
return;
|
|
}
|
|
throw new IllegalArgumentException("Can not set mcc for config size="+getConfigSize());
|
|
}
|
|
mValuesContainer.putShort(OFFSET_mcc, value);
|
|
}
|
|
public int getMcc(){
|
|
if(getConfigSize()<SIZE_16){
|
|
return 0;
|
|
}
|
|
return mValuesContainer.getShortUnsigned(OFFSET_mcc);
|
|
}
|
|
public void setMnc(int value){
|
|
if(getConfigSize()<SIZE_16){
|
|
if(value==0){
|
|
return;
|
|
}
|
|
throw new IllegalArgumentException("Can not set mnc for config size="+getConfigSize());
|
|
}
|
|
mValuesContainer.putShort(OFFSET_mnc, value);
|
|
}
|
|
public int getMnc(){
|
|
if(getConfigSize()<SIZE_16){
|
|
return 0;
|
|
}
|
|
return mValuesContainer.getShortUnsigned(OFFSET_mnc);
|
|
}
|
|
|
|
public byte[] getLanguageBytes(){
|
|
if(getConfigSize()<SIZE_16){
|
|
return new byte[2];
|
|
}
|
|
return mValuesContainer.getByteArray(OFFSET_language, 2);
|
|
}
|
|
public void setLanguageBytes(byte[] bytes){
|
|
if(getConfigSize()<SIZE_16){
|
|
if(isNull(bytes)){
|
|
return;
|
|
}
|
|
throw new IllegalArgumentException("Can not set language bytes for config size="+getConfigSize());
|
|
}
|
|
mValuesContainer.putByteArray(OFFSET_language, bytes);
|
|
}
|
|
public char[] getLanguageChars(){
|
|
byte[] bytes = getLanguageBytes();
|
|
return unPackLanguage(bytes[0], bytes[1]);
|
|
}
|
|
public void setLanguage(char[] chars){
|
|
setLanguageBytes(packLanguage(chars));
|
|
}
|
|
public void setLanguage(String language){
|
|
char[] chs = null;
|
|
if(language!=null){
|
|
chs=language.toCharArray();
|
|
}
|
|
setLanguage(chs);
|
|
}
|
|
public String getLanguage(){
|
|
char[] chars = getLanguageChars();
|
|
if(isNull(chars)){
|
|
return null;
|
|
}
|
|
return new String(chars);
|
|
}
|
|
|
|
public byte[] getRegionBytes(){
|
|
if(getConfigSize()<SIZE_16){
|
|
return new byte[2];
|
|
}
|
|
return mValuesContainer.getByteArray(OFFSET_region, 2);
|
|
}
|
|
public void setRegionBytes(byte[] bytes){
|
|
if(getConfigSize()<SIZE_16){
|
|
if(isNull(bytes)){
|
|
return;
|
|
}
|
|
throw new IllegalArgumentException("Can not set region bytes for config size="+getConfigSize());
|
|
}
|
|
mValuesContainer.putByteArray(OFFSET_region, bytes);
|
|
}
|
|
public char[] getRegionChars(){
|
|
byte[] bytes = getRegionBytes();
|
|
return unPackRegion(bytes[0], bytes[1]);
|
|
}
|
|
public void setRegion(char[] chars){
|
|
setRegionBytes(packRegion(chars));
|
|
}
|
|
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);
|
|
}
|
|
public String getRegion(){
|
|
char[] chars = getRegionChars();
|
|
if(isNull(chars)){
|
|
return null;
|
|
}
|
|
return new String(chars);
|
|
}
|
|
public void setOrientation(int orientation){
|
|
if(getConfigSize()<SIZE_16){
|
|
if(orientation==0){
|
|
return;
|
|
}
|
|
throw new IllegalArgumentException("Can not set orientation for config size="+getConfigSize());
|
|
}
|
|
mValuesContainer.putByte(OFFSET_orientation, orientation);
|
|
}
|
|
public int getOrientationValue(){
|
|
if(getConfigSize()<SIZE_16){
|
|
return 0;
|
|
}
|
|
return mValuesContainer.getByteUnsigned(OFFSET_orientation);
|
|
}
|
|
public Orientation getOrientation(){
|
|
return Orientation.valueOf(getOrientationValue());
|
|
}
|
|
public void setOrientation(Orientation orientation){
|
|
setOrientation(Orientation.update(orientation, getOrientationValue()));
|
|
}
|
|
public void setTouchscreen(int touchscreen){
|
|
if(getConfigSize()<SIZE_16){
|
|
if(touchscreen==0){
|
|
return;
|
|
}
|
|
throw new IllegalArgumentException("Can not set touchscreen for config size="+getConfigSize());
|
|
}
|
|
mValuesContainer.putByte(OFFSET_touchscreen, touchscreen);
|
|
}
|
|
public int getTouchscreenValue(){
|
|
if(getConfigSize()<SIZE_16){
|
|
return 0;
|
|
}
|
|
return mValuesContainer.getByteUnsigned(OFFSET_touchscreen);
|
|
}
|
|
public Touchscreen getTouchscreen(){
|
|
return Touchscreen.valueOf(getTouchscreenValue());
|
|
}
|
|
public void setTouchscreen(Touchscreen touchscreen){
|
|
setTouchscreen(Touchscreen.update(touchscreen, getTouchscreenValue()));
|
|
}
|
|
public void setDensity(int density){
|
|
if(getConfigSize()<SIZE_16){
|
|
if(density==0){
|
|
return;
|
|
}
|
|
throw new IllegalArgumentException("Can not set density for config size="+getConfigSize());
|
|
}
|
|
mValuesContainer.putShort(OFFSET_density, density);
|
|
}
|
|
public int getDensityValue(){
|
|
if(getConfigSize()<SIZE_16){
|
|
return 0;
|
|
}
|
|
return mValuesContainer.getShortUnsigned(OFFSET_density);
|
|
}
|
|
public Density getDensity(){
|
|
return Density.valueOf(getDensityValue());
|
|
}
|
|
public void setDensity(Density density){
|
|
setDensity(Density.update(density, getDensityValue()));
|
|
}
|
|
public void setKeyboard(int keyboard){
|
|
if(getConfigSize()<SIZE_28){
|
|
if(keyboard==0){
|
|
return;
|
|
}
|
|
throw new IllegalArgumentException("Can not set keyboard for config size="+getConfigSize());
|
|
}
|
|
mValuesContainer.putByte(OFFSET_keyboard, keyboard);
|
|
}
|
|
public int getKeyboardValue(){
|
|
if(getConfigSize()<SIZE_28){
|
|
return 0;
|
|
}
|
|
return mValuesContainer.getByteUnsigned(OFFSET_keyboard);
|
|
}
|
|
public Keyboard getKeyboard(){
|
|
return Keyboard.valueOf(getKeyboardValue());
|
|
}
|
|
public void setKeyboard(Keyboard keyboard){
|
|
setKeyboard(Keyboard.update(keyboard, getKeyboardValue()));
|
|
}
|
|
public void setNavigation(int navigation){
|
|
if(getConfigSize()<SIZE_28){
|
|
if(navigation==0){
|
|
return;
|
|
}
|
|
throw new IllegalArgumentException("Can not set navigation for config size="+getConfigSize());
|
|
}
|
|
mValuesContainer.putByte(OFFSET_navigation, navigation);
|
|
}
|
|
public int getNavigationValue(){
|
|
if(getConfigSize()<SIZE_28){
|
|
return 0;
|
|
}
|
|
return mValuesContainer.getByteUnsigned(OFFSET_navigation);
|
|
}
|
|
public Navigation getNavigation(){
|
|
return Navigation.valueOf(getNavigationValue());
|
|
}
|
|
public void setNavigation(Navigation navigation){
|
|
setNavigation(Navigation.update(navigation, getNavigationValue()));
|
|
}
|
|
public void setInputFlags(int inputFlags){
|
|
if(getConfigSize()<SIZE_28){
|
|
if(inputFlags==0){
|
|
return;
|
|
}
|
|
throw new IllegalArgumentException("Can not set inputFlags for config size="+getConfigSize());
|
|
}
|
|
mValuesContainer.putByte(OFFSET_inputFlags, inputFlags);
|
|
}
|
|
public int getInputFlagsValue(){
|
|
if(getConfigSize()<SIZE_28){
|
|
return 0;
|
|
}
|
|
return mValuesContainer.getByteUnsigned(OFFSET_inputFlags);
|
|
}
|
|
public InputFlagsKeysHidden getInputFlagsKeysHidden(){
|
|
return InputFlagsKeysHidden.valueOf(getInputFlagsValue());
|
|
}
|
|
public void setInputFlagsKeysHidden(InputFlagsKeysHidden keysHidden){
|
|
setInputFlags(InputFlagsKeysHidden.update(keysHidden, getInputFlagsValue()));
|
|
}
|
|
public InputFlagsNavHidden getInputFlagsNavHidden(){
|
|
return InputFlagsNavHidden.valueOf(getInputFlagsValue());
|
|
}
|
|
public void setInputFlagsNavHidden(InputFlagsNavHidden navHidden){
|
|
setInputFlags(InputFlagsNavHidden.update(navHidden, getInputFlagsValue()));
|
|
}
|
|
public void setInputPad0(byte b){
|
|
if(getConfigSize()<SIZE_28){
|
|
if(b==0){
|
|
return;
|
|
}
|
|
throw new IllegalArgumentException("Can not set inputPad0 for config size="+getConfigSize());
|
|
}
|
|
mValuesContainer.put(OFFSET_inputPad0, b);
|
|
}
|
|
public byte getInputPad0(){
|
|
if(getConfigSize()<SIZE_28){
|
|
return 0;
|
|
}
|
|
return mValuesContainer.get(OFFSET_inputPad0);
|
|
}
|
|
public void setScreenWidth(int value){
|
|
if(getConfigSize()<SIZE_28){
|
|
if(value==0){
|
|
return;
|
|
}
|
|
throw new IllegalArgumentException("Can not set screenWidth for config size="+getConfigSize());
|
|
}
|
|
mValuesContainer.putShort(OFFSET_screenWidth, value);
|
|
}
|
|
public int getScreenWidth(){
|
|
if(getConfigSize()<SIZE_28){
|
|
return 0;
|
|
}
|
|
return mValuesContainer.getShortUnsigned(OFFSET_screenWidth);
|
|
}
|
|
public void setScreenHeight(int value){
|
|
if(getConfigSize()<SIZE_28){
|
|
if(value==0){
|
|
return;
|
|
}
|
|
throw new IllegalArgumentException("Can not set screenHeight for config size="+getConfigSize());
|
|
}
|
|
mValuesContainer.putShort(OFFSET_screenHeight, value);
|
|
}
|
|
public int getScreenHeight(){
|
|
if(getConfigSize()<SIZE_28){
|
|
return 0;
|
|
}
|
|
return mValuesContainer.getShortUnsigned(OFFSET_screenHeight);
|
|
}
|
|
public void setScreenSize(int width, int height){
|
|
this.setScreenWidth(width);
|
|
this.setScreenHeight(height);
|
|
}
|
|
public void setSdkVersion(int value){
|
|
if(getConfigSize()<SIZE_28){
|
|
if(value==0){
|
|
return;
|
|
}
|
|
throw new IllegalArgumentException("Can not set sdkVersion for config size="+getConfigSize());
|
|
}
|
|
mValuesContainer.putShort(OFFSET_sdkVersion, value);
|
|
}
|
|
public int getSdkVersion(){
|
|
if(getConfigSize()<SIZE_28){
|
|
return 0;
|
|
}
|
|
return mValuesContainer.getShortUnsigned(OFFSET_sdkVersion);
|
|
}
|
|
public void setMinorVersion(int value){
|
|
if(getConfigSize()<SIZE_28){
|
|
if(value==0){
|
|
return;
|
|
}
|
|
throw new IllegalArgumentException("Can not set minorVersion for config size="+getConfigSize());
|
|
}
|
|
mValuesContainer.putShort(OFFSET_minorVersion, value);
|
|
}
|
|
public int getMinorVersion(){
|
|
if(getConfigSize()<SIZE_28){
|
|
return 0;
|
|
}
|
|
return mValuesContainer.getShortUnsigned(OFFSET_minorVersion);
|
|
}
|
|
public void setScreenLayout(int layout){
|
|
if(getConfigSize()<SIZE_32){
|
|
if(layout==0){
|
|
return;
|
|
}
|
|
throw new IllegalArgumentException("Can not set screenLayout for config size="+getConfigSize());
|
|
}
|
|
mValuesContainer.putByte(OFFSET_screenLayout, layout);
|
|
}
|
|
public int getScreenLayout(){
|
|
if(getConfigSize()<SIZE_32){
|
|
return 0;
|
|
}
|
|
return mValuesContainer.getByteUnsigned(OFFSET_screenLayout);
|
|
}
|
|
public ScreenLayoutSize getScreenLayoutSize(){
|
|
return ScreenLayoutSize.valueOf(getScreenLayout());
|
|
}
|
|
public void setScreenLayoutSize(ScreenLayoutSize layoutSize){
|
|
setScreenLayout(ScreenLayoutSize.update(layoutSize, getScreenLayout()));
|
|
}
|
|
public ScreenLayoutLong getScreenLayoutLong(){
|
|
return ScreenLayoutLong.valueOf(getScreenLayout());
|
|
}
|
|
public void setScreenLayoutLong(ScreenLayoutLong layoutLong){
|
|
setScreenLayout(ScreenLayoutLong.update(layoutLong, getScreenLayout()));
|
|
}
|
|
public ScreenLayoutDir getScreenLayoutDir(){
|
|
return ScreenLayoutDir.valueOf(getScreenLayout());
|
|
}
|
|
public void setScreenLayoutDir(ScreenLayoutDir layoutDir){
|
|
setScreenLayout(ScreenLayoutDir.update(layoutDir, getScreenLayout()));
|
|
}
|
|
public void setUiMode(int mode){
|
|
if(getConfigSize()<SIZE_32){
|
|
if(mode==0){
|
|
return;
|
|
}
|
|
throw new IllegalArgumentException("Can not set uiMode for config size="+getConfigSize());
|
|
}
|
|
mValuesContainer.putByte(OFFSET_uiMode, mode);
|
|
}
|
|
public int getUiMode(){
|
|
if(getConfigSize()<SIZE_32){
|
|
return 0;
|
|
}
|
|
return mValuesContainer.getByteUnsigned(OFFSET_uiMode);
|
|
}
|
|
public UiModeType getUiModeType(){
|
|
return UiModeType.valueOf(getUiMode());
|
|
}
|
|
public void setUiModeType(UiModeType uiModeType){
|
|
setUiMode(UiModeType.update(uiModeType, getUiMode()));
|
|
}
|
|
public UiModeNight getUiModeNight(){
|
|
return UiModeNight.valueOf(getUiMode());
|
|
}
|
|
public void setUiModeNight(UiModeNight uiModeNight){
|
|
setUiMode(UiModeNight.update(uiModeNight, getUiMode()));
|
|
}
|
|
public void setSmallestScreenWidthDp(int value){
|
|
if(getConfigSize()<SIZE_32){
|
|
if(value==0){
|
|
return;
|
|
}
|
|
throw new IllegalArgumentException("Can not set smallestScreenWidthDp for config size="+getConfigSize());
|
|
}
|
|
mValuesContainer.putShort(OFFSET_smallestScreenWidthDp, value);
|
|
}
|
|
public int getSmallestScreenWidthDp(){
|
|
if(getConfigSize()<SIZE_32){
|
|
return 0;
|
|
}
|
|
return mValuesContainer.getShortUnsigned(OFFSET_smallestScreenWidthDp);
|
|
}
|
|
public void setScreenWidthDp(int value){
|
|
if(getConfigSize()<SIZE_36){
|
|
if(value==0){
|
|
return;
|
|
}
|
|
throw new IllegalArgumentException("Can not set screenWidthDp for config size="+getConfigSize());
|
|
}
|
|
mValuesContainer.putShort(OFFSET_screenWidthDp, value);
|
|
}
|
|
public int getScreenWidthDp(){
|
|
if(getConfigSize()<SIZE_36){
|
|
return 0;
|
|
}
|
|
return mValuesContainer.getShortUnsigned(OFFSET_screenWidthDp);
|
|
}
|
|
public void setScreenHeightDp(int value){
|
|
if(getConfigSize()<SIZE_36){
|
|
if(value==0){
|
|
return;
|
|
}
|
|
throw new IllegalArgumentException("Can not set screenHeightDp for config size="+getConfigSize());
|
|
}
|
|
mValuesContainer.putShort(OFFSET_screenHeightDp, value);
|
|
}
|
|
public int getScreenHeightDp(){
|
|
if(getConfigSize()<SIZE_36){
|
|
return 0;
|
|
}
|
|
return mValuesContainer.getShortUnsigned(OFFSET_screenHeightDp);
|
|
}
|
|
public void setLocaleScript(byte[] bts){
|
|
if(getConfigSize()<SIZE_48){
|
|
if(isNull(bts)){
|
|
return;
|
|
}
|
|
throw new IllegalArgumentException("Can not set localeScript for config size="+getConfigSize());
|
|
}
|
|
bts = ensureArrayLength(bts, LEN_localeScript);
|
|
mValuesContainer.putByteArray(OFFSET_localeScript, bts);
|
|
}
|
|
public void setLocaleScript(char[] chs){
|
|
byte[] bts=toByteArray(chs, LEN_localeScript);
|
|
setLocaleScript(bts);
|
|
}
|
|
public void setLocaleScript(String script){
|
|
char[] chs = null;
|
|
script = trimPostfix(script, POSTFIX_locale);
|
|
if(script!=null){
|
|
chs = script.toCharArray();
|
|
}
|
|
setLocaleScript(chs);
|
|
}
|
|
public char[] getLocaleScriptChars(){
|
|
if(getConfigSize()<SIZE_48){
|
|
return null;
|
|
}
|
|
byte[] bts = mValuesContainer.getByteArray(OFFSET_localeScript, LEN_localeScript);
|
|
return trimEndingZero(toCharArray(bts));
|
|
}
|
|
private String getLocaleScriptInternal(){
|
|
char[] chs = getLocaleScriptChars();
|
|
if(chs==null){
|
|
return null;
|
|
}
|
|
return new String(chs);
|
|
}
|
|
public String getLocaleScript(){
|
|
String script = getLocaleScriptInternal();
|
|
if(script==null){
|
|
return null;
|
|
}
|
|
script = ensureLength(script, 3, POSTFIX_locale);
|
|
return script;
|
|
}
|
|
public void setLocaleVariant(byte[] bts){
|
|
if(getConfigSize()<SIZE_48){
|
|
if(isNull(bts)){
|
|
return;
|
|
}
|
|
throw new IllegalArgumentException("Can not set localeVariant for config size="+getConfigSize());
|
|
}
|
|
bts = ensureArrayLength(bts, LEN_localeVariant);
|
|
mValuesContainer.putByteArray(OFFSET_localeVariant, bts);
|
|
}
|
|
public void setLocaleVariant(char[] chs){
|
|
byte[] bts=toByteArray(chs, LEN_localeVariant);
|
|
setLocaleVariant(bts);
|
|
}
|
|
public void setLocaleVariant(String variant){
|
|
if(variant!=null){
|
|
variant = variant.toLowerCase();
|
|
}
|
|
setLocaleVariantInternal(variant);
|
|
}
|
|
private void setLocaleVariantInternal(String variant){
|
|
char[] chs = null;
|
|
variant = trimPostfix(variant, POSTFIX_locale);
|
|
if(variant!=null){
|
|
chs = variant.toCharArray();
|
|
}
|
|
setLocaleVariant(chs);
|
|
}
|
|
public char[] getLocaleVariantChars(){
|
|
if(getConfigSize()<SIZE_48){
|
|
return null;
|
|
}
|
|
byte[] bts = mValuesContainer.getByteArray(OFFSET_localeVariant, LEN_localeVariant);
|
|
return trimEndingZero(toCharArray(bts));
|
|
}
|
|
private String getLocaleVariantInternal(){
|
|
char[] chs = getLocaleVariantChars();
|
|
if(chs==null){
|
|
return null;
|
|
}
|
|
return new String(chs);
|
|
}
|
|
public String getLocaleVariant(){
|
|
String variant = getLocaleVariantInternal();
|
|
if(variant==null){
|
|
return null;
|
|
}
|
|
variant = ensureLength(variant, 5, POSTFIX_locale);
|
|
return variant.toUpperCase();
|
|
}
|
|
public void setScreenLayout2(int screenLayout2){
|
|
if(getConfigSize()<SIZE_52){
|
|
if(screenLayout2==0){
|
|
return;
|
|
}
|
|
throw new IllegalArgumentException("Can not set screenLayout2 for config size="+getConfigSize());
|
|
}
|
|
mValuesContainer.putByte(OFFSET_screenLayout2, screenLayout2);
|
|
}
|
|
public int getScreenLayout2(){
|
|
if(getConfigSize()<SIZE_52){
|
|
return 0;
|
|
}
|
|
return mValuesContainer.getByteUnsigned(OFFSET_screenLayout2);
|
|
}
|
|
public ScreenLayoutRound getScreenLayoutRound(){
|
|
return ScreenLayoutRound.valueOf(getScreenLayout2());
|
|
}
|
|
public void setScreenLayoutRound(ScreenLayoutRound layoutRound){
|
|
setScreenLayout2(ScreenLayoutRound.update(layoutRound, getScreenLayout2()));
|
|
}
|
|
public void setColorMode(int colorMode){
|
|
if(getConfigSize()<SIZE_56){
|
|
if(colorMode==0){
|
|
return;
|
|
}
|
|
throw new IllegalArgumentException("Can not set colorMode for config size="+getConfigSize());
|
|
}
|
|
mValuesContainer.putByte(OFFSET_colorMode, colorMode);
|
|
}
|
|
public int getColorMode(){
|
|
if(getConfigSize()<SIZE_56){
|
|
return 0;
|
|
}
|
|
return mValuesContainer.getByteUnsigned(OFFSET_colorMode);
|
|
}
|
|
public ColorModeWide getColorModeWide(){
|
|
return ColorModeWide.valueOf(getColorMode());
|
|
}
|
|
public void setColorModeWide(ColorModeWide colorModeWide){
|
|
setColorMode(ColorModeWide.update(colorModeWide, getColorMode()));
|
|
}
|
|
public ColorModeHdr getColorModeHdr(){
|
|
return ColorModeHdr.valueOf(getColorMode());
|
|
}
|
|
public void setColorModeHdr(ColorModeHdr colorModeHdr){
|
|
setColorMode(ColorModeHdr.update(colorModeHdr, getColorMode()));
|
|
}
|
|
public void setLocaleNumberingSystem(byte[] bts){
|
|
if(getConfigSize()<SIZE_64){
|
|
if(isNull(bts)){
|
|
return;
|
|
}
|
|
throw new IllegalArgumentException("Can not set localeNumberingSystem for config size="+getConfigSize());
|
|
}
|
|
bts = ensureArrayLength(bts, LEN_localeNumberingSystem);
|
|
mValuesContainer.putByteArray(OFFSET_localeNumberingSystem, bts);
|
|
}
|
|
public String getLocaleNumberingSystem(){
|
|
char[] chars = getLocaleNumberingSystemChars();
|
|
if(isNull(chars)){
|
|
return null;
|
|
}
|
|
return new String(chars);
|
|
}
|
|
public char[] getLocaleNumberingSystemChars(){
|
|
if(getConfigSize()<SIZE_64){
|
|
return null;
|
|
}
|
|
byte[] bts = mValuesContainer.getByteArray(OFFSET_localeNumberingSystem, LEN_localeNumberingSystem);
|
|
return trimEndingZero(toCharArray(bts));
|
|
}
|
|
public void setLocaleNumberingSystem(char[] chs){
|
|
byte[] bts=toByteArray(chs, LEN_localeNumberingSystem);
|
|
setLocaleNumberingSystem(bts);
|
|
}
|
|
public void setLocaleNumberingSystem(String numberingSystem){
|
|
char[] chars = null;
|
|
if(numberingSystem!=null){
|
|
chars = numberingSystem.toCharArray();
|
|
}
|
|
setLocaleNumberingSystem(chars);
|
|
}
|
|
|
|
public String getQualifiers(){
|
|
int hash = this.hashCode();
|
|
if(mQualifiers==null || mQualifiersStamp!=hash){
|
|
mQualifiers = new QualifierBuilder(this).build();
|
|
mQualifiersStamp = hash;
|
|
}
|
|
return mQualifiers;
|
|
}
|
|
|
|
public boolean isEqualQualifiers(String qualifiers){
|
|
return this.equals(parse(qualifiers));
|
|
}
|
|
public boolean isDefault(){
|
|
return isNull(mValuesContainer.getBytes());
|
|
}
|
|
@Override
|
|
public JSONObject toJson() {
|
|
JSONObject jsonObject=new JSONObject();
|
|
if(isDefault()){
|
|
return jsonObject;
|
|
}
|
|
int val=getMcc();
|
|
if(val!=0){
|
|
jsonObject.put(NAME_mcc, val);
|
|
}
|
|
val=getMnc();
|
|
if(val!=0){
|
|
jsonObject.put(NAME_mnc, val);
|
|
}
|
|
String str=getLanguage();
|
|
if(str!=null){
|
|
jsonObject.put(NAME_language, str);
|
|
}
|
|
str=getRegion();
|
|
if(str!=null){
|
|
jsonObject.put(NAME_region, str);
|
|
}
|
|
jsonObject.put(NAME_orientation, Flag.toString(getOrientation()));
|
|
jsonObject.put(NAME_touchscreen, Flag.toString(getTouchscreen()));
|
|
jsonObject.put(NAME_density, Flag.toString(getDensity()));
|
|
jsonObject.put(NAME_keyboard, Flag.toString(getKeyboard()));
|
|
jsonObject.put(NAME_navigation, Flag.toString(getNavigation()));
|
|
jsonObject.put(NAME_input_flags_keys_hidden, Flag.toString(getInputFlagsKeysHidden()));
|
|
jsonObject.put(NAME_input_flags_nav_hidden, Flag.toString(getInputFlagsNavHidden()));
|
|
val = getScreenWidth();
|
|
if(val!=0){
|
|
jsonObject.put(NAME_screenWidth, val);
|
|
}
|
|
val = getScreenHeight();
|
|
if(val!=0){
|
|
jsonObject.put(NAME_screenHeight, val);
|
|
}
|
|
val = getSdkVersion();
|
|
if(val!=0){
|
|
jsonObject.put(NAME_sdkVersion, val);
|
|
}
|
|
val = getMinorVersion();
|
|
if(val!=0){
|
|
jsonObject.put(NAME_minorVersion, val);
|
|
}
|
|
jsonObject.put(NAME_screen_layout_size, Flag.toString(getScreenLayoutSize()));
|
|
jsonObject.put(NAME_screen_layout_long, Flag.toString(getScreenLayoutLong()));
|
|
jsonObject.put(NAME_screen_layout_dir, Flag.toString(getScreenLayoutDir()));
|
|
jsonObject.put(NAME_ui_mode_type, Flag.toString(getUiModeType()));
|
|
jsonObject.put(NAME_ui_mode_night, Flag.toString(getUiModeNight()));
|
|
val = getSmallestScreenWidthDp();
|
|
if(val!=0){
|
|
jsonObject.put(NAME_smallestScreenWidthDp, val);
|
|
}
|
|
val = getScreenWidthDp();
|
|
if(val!=0){
|
|
jsonObject.put(NAME_screenWidthDp, val);
|
|
}
|
|
val = getScreenHeightDp();
|
|
if(val!=0){
|
|
jsonObject.put(NAME_screenHeightDp, val);
|
|
}
|
|
str = getLocaleScriptInternal();
|
|
if(str!=null){
|
|
jsonObject.put(NAME_localeScript, str);
|
|
}
|
|
str = getLocaleVariantInternal();
|
|
if(str!=null){
|
|
jsonObject.put(NAME_localeVariant, str);
|
|
}
|
|
jsonObject.put(NAME_screen_layout_round, Flag.toString(getScreenLayoutRound()));
|
|
jsonObject.put(NAME_color_mode_wide, Flag.toString(getColorModeWide()));
|
|
jsonObject.put(NAME_color_mode_hdr, Flag.toString(getColorModeHdr()));
|
|
str = getLocaleNumberingSystem();
|
|
if(str!=null){
|
|
jsonObject.put(NAME_localeNumberingSystem, str);
|
|
}
|
|
return jsonObject;
|
|
}
|
|
@Override
|
|
public void fromJson(JSONObject json) {
|
|
if(json.isEmpty()){
|
|
mValuesContainer.fill((byte) 0);
|
|
return;
|
|
}
|
|
trimToSize(SIZE_64);
|
|
|
|
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)));
|
|
setTouchscreen(Touchscreen.valueOf(json.optString(NAME_touchscreen)));
|
|
setDensity(Density.valueOf(json.optString(NAME_density)));
|
|
setKeyboard(Keyboard.valueOf(json.optString(NAME_keyboard)));
|
|
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(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(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)));
|
|
setColorModeWide(ColorModeWide.valueOf(json.optString(NAME_color_mode_wide)));
|
|
setColorModeHdr(ColorModeHdr.valueOf(json.optString(NAME_color_mode_hdr)));
|
|
setLocaleNumberingSystem(json.optString(NAME_localeNumberingSystem));
|
|
trimToSize(SIZE_48);
|
|
}
|
|
@Override
|
|
public int hashCode(){
|
|
byte[] bts = ByteArray.trimTrailZeros(mValuesContainer.getBytes());
|
|
return Arrays.hashCode(bts);
|
|
}
|
|
@Override
|
|
public boolean equals(Object obj){
|
|
if(obj==this){
|
|
return true;
|
|
}
|
|
if(obj==null){
|
|
return false;
|
|
}
|
|
if(obj instanceof ResConfig){
|
|
ResConfig other = (ResConfig)obj;
|
|
byte[] bts1 = mValuesContainer.getBytes();
|
|
byte[] bts2 = other.mValuesContainer.getBytes();
|
|
return ByteArray.equalsIgnoreTrailZero(bts1, bts2);
|
|
}
|
|
return false;
|
|
}
|
|
@Override
|
|
public String toString(){
|
|
String q=getQualifiers();
|
|
if(q.length()==0){
|
|
q="DEFAULT";
|
|
}
|
|
return "["+q+"]";
|
|
}
|
|
@Override
|
|
public int compareTo(ResConfig resConfig) {
|
|
return getQualifiers().compareTo(resConfig.getQualifiers());
|
|
}
|
|
|
|
public static ResConfig parse(String qualifiers){
|
|
ResConfig resConfig = new ResConfig();
|
|
resConfig.parseQualifiers(qualifiers);
|
|
return resConfig;
|
|
}
|
|
public static int nearestSize(int size){
|
|
if(size <= SIZE_16){
|
|
return SIZE_16;
|
|
}
|
|
if(size <= SIZE_28){
|
|
return SIZE_28;
|
|
}
|
|
if(size <= SIZE_32){
|
|
return SIZE_32;
|
|
}
|
|
if(size <= SIZE_36){
|
|
return SIZE_36;
|
|
}
|
|
if(size <= SIZE_48){
|
|
return SIZE_48;
|
|
}
|
|
if(size <= SIZE_52){
|
|
return SIZE_52;
|
|
}
|
|
if(size <= SIZE_56){
|
|
return SIZE_56;
|
|
}
|
|
return SIZE_64;
|
|
}
|
|
|
|
|
|
private static char[] unPackLanguage(byte in0, byte in1) {
|
|
return unpackLanguageOrRegion(in0, in1, 'a');
|
|
}
|
|
private static char[] unPackRegion(byte in0, byte in1) {
|
|
return unpackLanguageOrRegion(in0, in1, '0');
|
|
}
|
|
private static char[] unpackLanguageOrRegion(byte in0, byte in1, char base) {
|
|
char[] out;
|
|
if ((in0 & 0x80) !=0) {
|
|
out = new char[3];
|
|
byte first = (byte) (in1 & 0x1f);
|
|
byte second = (byte) (((in1 & 0xe0) >> 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 extends Flag> T fromQualifiers(T[] values, String qualifiers){
|
|
if(qualifiers == null){
|
|
return null;
|
|
}
|
|
return fromQualifiers(values, qualifiers.split("\\s*-\\s*"));
|
|
}
|
|
static<T extends Flag> 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 extends Flag> 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 extends Flag> 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(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){
|
|
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;
|
|
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 = '#';
|
|
|
|
}
|