1 package org.coolreader.crengine; 2 3 import android.app.Application; 4 import android.graphics.PixelFormat; 5 import android.os.Build; 6 import android.util.Log; 7 8 import com.onyx.android.sdk.api.device.epd.EpdController; 9 import com.onyx.android.sdk.device.Device; 10 import com.onyx.android.sdk.utils.ReflectUtil; 11 12 import java.lang.reflect.Field; 13 import java.lang.reflect.Method; 14 import java.util.List; 15 16 public class DeviceInfo { 17 18 public final static String MANUFACTURER; 19 public final static String MODEL; 20 public final static String DEVICE; 21 public final static String PRODUCT; 22 public final static String BRAND; 23 public final static int MIN_SCREEN_BRIGHTNESS_VALUE; 24 public final static int MAX_SCREEN_BRIGHTNESS_VALUE; 25 public final static int MAX_SCREEN_BRIGHTNESS_WARM_VALUE; 26 public final static boolean SAMSUNG_BUTTONS_HIGHLIGHT_PATCH; 27 public final static boolean EINK_SCREEN; 28 public final static boolean EINK_SCREEN_REGAL; 29 public final static boolean EINK_HAVE_FRONTLIGHT; 30 public final static boolean EINK_HAVE_NATURAL_BACKLIGHT; 31 public final static boolean EINK_SCREEN_UPDATE_MODES_SUPPORTED; 32 public final static boolean NOOK_NAVIGATION_KEYS; 33 public final static boolean EINK_NOOK; 34 public final static boolean EINK_NOOK_120; 35 public final static boolean EINK_ONYX; 36 public final static boolean EINK_DNS; 37 public final static boolean EINK_TOLINO; 38 public final static boolean FORCE_HC_THEME; 39 public final static boolean EINK_SONY; 40 public final static boolean EINK_ENERGYSYSTEM; 41 public final static boolean SONY_NAVIGATION_KEYS; 42 public final static boolean USE_CUSTOM_TOAST; 43 public final static boolean AMOLED_SCREEN; 44 public final static boolean POCKETBOOK; 45 public final static boolean ONYX_BUTTONS_LONG_PRESS_NOT_AVAILABLE; 46 public final static boolean ONYX_HAVE_FRONTLIGHT; 47 public final static boolean ONYX_HAVE_NATURAL_BACKLIGHT; 48 public final static boolean ONYX_HAVE_BRIGHTNESS_SYSTEM_DIALOG; 49 public final static boolean NOFLIBUSTA; 50 public final static boolean NAVIGATE_LEFTRIGHT; // map left/right keys to single page flip 51 public final static boolean REVERT_LANDSCAPE_VOLUME_KEYS; // revert volume keys in landscape mode 52 public final static android.graphics.Bitmap.Config BUFFER_COLOR_FORMAT; 53 public final static boolean USE_OPENGL = true; 54 public final static int PIXEL_FORMAT; 55 public final static String DEF_FONT_FACE; 56 public final static boolean USE_BITMAP_MEMORY_HACK; // revert volume keys in landscape mode 57 public final static Integer DEF_FONT_SIZE; 58 public final static boolean ONE_COLUMN_IN_LANDSCAPE; 59 60 // minimal screen backlight level percent for different devices 61 private static final String[] MIN_SCREEN_BRIGHTNESS_DB = { 62 "LGE;LG-P500", "6", // LG Optimus One 63 "samsung;GT-I9003", "6", // Samsung i9003 64 "Samsung;GT-I9000", "1", // Samsung Galaxy S 65 "Samsung;GT-I9100", "1", // Samsung Galaxy S2 66 "Samsung;GT-I9300", "1", // Samsung Galaxy S3 67 "Samsung;GT-I9500", "1", // Samsung Galaxy S4 68 "HTC;HTC EVO 3D*", "1", // HTC EVO 69 "Archos;A70S", "1", // Archos 70 "HTC;HTC Desire", "6", // HTC Desire 71 "HTC;HTC Desire S", "6", 72 "HTC;HTC Incredible*","6",// HTC Incredible, HTC Incredible S 73 "HTC;Legend", "6", 74 "LGE;LG-E510", "6", 75 "*;Kindle Fire", "6", 76 "Samsung;GT-S5830", "6", 77 "HUAWEI;U8800", "6", 78 "Motorola;Milestone XT720", "6", 79 "Foxconn;PocketBook A10", "3", 80 "*;*;*;tolino", "1", 81 // TODO: more devices here 82 }; 83 84 public final static int ICE_CREAM_SANDWICH = 14; 85 public final static int HONEYCOMB = 11; 86 87 private static int sdkInt = 0; getSDKLevel()88 public static int getSDKLevel() { 89 if (sdkInt > 0) 90 return sdkInt; 91 // hack for Android 1.5 92 sdkInt = 3; 93 Field fld; 94 try { 95 Class<?> cl = android.os.Build.VERSION.class; 96 fld = cl.getField("SDK_INT"); 97 sdkInt = fld.getInt(cl); 98 Log.i("cr3", "API LEVEL " + sdkInt + " detected"); 99 } catch (SecurityException e) { 100 // ignore 101 } catch (NoSuchFieldException e) { 102 // ignore 103 } catch (IllegalArgumentException e) { 104 // ignore 105 } catch (IllegalAccessException e) { 106 // ignore 107 } 108 return sdkInt; 109 } 110 supportsActionBar()111 public static boolean supportsActionBar() { 112 return getSDKLevel() >= HONEYCOMB; 113 } 114 115 static { 116 MANUFACTURER = getBuildField("MANUFACTURER"); 117 MODEL = getBuildField("MODEL"); 118 DEVICE = getBuildField("DEVICE"); 119 PRODUCT = getBuildField("PRODUCT"); 120 BRAND = getBuildField("BRAND"); 121 SAMSUNG_BUTTONS_HIGHLIGHT_PATCH = MANUFACTURER.toLowerCase().contentEquals("samsung") && 122 (MODEL.contentEquals("GT-S5830") || MODEL.contentEquals("GT-S5660")); // More models? 123 AMOLED_SCREEN = MANUFACTURER.toLowerCase().contentEquals("samsung") && 124 (MODEL.toLowerCase().startsWith("gt-i")); // AMOLED screens: GT-IXXXX 125 EINK_NOOK = MANUFACTURER.toLowerCase().contentEquals("barnesandnoble") && 126 (PRODUCT.contentEquals("NOOK") || MODEL.contentEquals("NOOK") || MODEL.contentEquals("BNRV350") || MODEL.contentEquals("BNRV300") || MODEL.contentEquals("BNRV500")) && 127 DEVICE.toLowerCase().contentEquals("zoom2"); 128 EINK_NOOK_120 = EINK_NOOK && (MODEL.contentEquals("BNRV350") || MODEL.contentEquals("BNRV300") || MODEL.contentEquals("BNRV500")); 129 EINK_SONY = MANUFACTURER.toLowerCase().contentEquals("sony") && MODEL.startsWith("PRS-T"); 130 //MANUFACTURER=Onyx, MODEL=*; All ONYX BOOX Readers have e-ink screen 131 EINK_ONYX = (MANUFACTURER.toLowerCase().contentEquals("onyx") || MANUFACTURER.toLowerCase().contentEquals("onyx-intl")) && 132 (BRAND.toLowerCase().contentEquals("onyx") || BRAND.toLowerCase().contentEquals("maccentre") || BRAND.toLowerCase().contentEquals("maccenter")) && 133 MODEL.length() > 0; 134 EINK_ENERGYSYSTEM = ( 135 (BRAND.toLowerCase().contentEquals("energysistem")||BRAND.toLowerCase().contentEquals("energysystem")) && MODEL.toLowerCase().startsWith("ereader")); 136 //MANUFACTURER -DNS, DEVICE -BK6004C, MODEL - DNS Airbook EGH602, PRODUCT - BK6004C 137 EINK_DNS = MANUFACTURER.toLowerCase().contentEquals("dns") && MODEL.startsWith("DNS Airbook EGH"); 138 139 EINK_TOLINO = (BRAND.toLowerCase().contentEquals("tolino") && (MODEL.toLowerCase().contentEquals("imx50_rdp")) ) || // SHINE 140 (MODEL.toLowerCase().contentEquals("tolino") && DEVICE.toLowerCase().contentEquals("tolino_vision2")); //Tolino Vision HD4 doesn't show any Brand, only Model=tolino and DEVICE=tolino_vision2) 141 142 143 EINK_SCREEN = EINK_SONY || EINK_NOOK || EINK_ONYX || EINK_ENERGYSYSTEM || EINK_DNS || EINK_TOLINO; // TODO: set to true for eink devices like Nook Touch 144 145 // On Onyx Boox Monte Cristo 3 (and possible Monte Cristo, Monte Cristo 2) long press action on buttons are catch by system and not available for application 146 // TODO: check this on other ONYX BOOX Readers 147 ONYX_BUTTONS_LONG_PRESS_NOT_AVAILABLE = EINK_ONYX && MODEL.toLowerCase().startsWith("mc_kepler"); 148 boolean onyx_have_frontlight = false; 149 boolean onyx_have_natural_backlight = false; 150 int onyx_max_screen_brightness_value = 100; 151 int onyx_max_screen_brightness_warm_value = 100; 152 boolean onyx_support_regal = false; 153 boolean onyx_have_brightness_system_dialog = false; 154 if (EINK_ONYX) { 155 onyx_support_regal = EpdController.supportRegal(); 156 Class<?> clazz = ReflectUtil.classForName("android.app.ActivityThread"); 157 Method method = ReflectUtil.getMethodSafely(clazz, "currentApplication"); 158 Application app = (Application) ReflectUtil.invokeMethodSafely(method, null); 159 if (null != app) { 160 onyx_have_frontlight = Device.currentDevice().hasFLBrightness(app); 161 List<Integer> list = null; 162 try { 163 list = Device.currentDevice().getFrontLightValueList(app); 164 } catch (Exception ignored) {} 165 if (list != null && list.size() > 0) { 166 onyx_max_screen_brightness_value = list.get(list.size() - 1); 167 if (!onyx_have_frontlight) { 168 // For ONYX BOOX MC3 and may be other too... 169 onyx_have_frontlight = true; 170 } 171 } 172 // natural (cold & warm) backlight support 173 onyx_have_natural_backlight = Device.currentDevice().hasCTMBrightness(app); 174 if (onyx_have_natural_backlight) { 175 Integer[] values = Device.currentDevice().getWarmLightValues(app); 176 if (values != null && values.length > 0) { 177 onyx_max_screen_brightness_warm_value = values[values.length - 1]; 178 } 179 } 180 if (!onyx_have_frontlight && onyx_have_natural_backlight) { 181 onyx_have_frontlight = true; 182 Integer[] values = Device.currentDevice().getColdLightValues(app); 183 if (values != null && values.length > 0) { 184 onyx_max_screen_brightness_value = values[values.length - 1]; 185 } 186 } 187 } 188 switch (Device.currentDeviceIndex()) { 189 case Rk31xx: 190 case Rk32xx: 191 case Rk33xx: 192 case SDM: 193 onyx_have_brightness_system_dialog = true; 194 break; 195 } 196 } 197 ONYX_HAVE_BRIGHTNESS_SYSTEM_DIALOG = onyx_have_brightness_system_dialog; 198 ONYX_HAVE_FRONTLIGHT = onyx_have_frontlight; 199 ONYX_HAVE_NATURAL_BACKLIGHT = onyx_have_natural_backlight; 200 MAX_SCREEN_BRIGHTNESS_VALUE = onyx_max_screen_brightness_value; 201 MAX_SCREEN_BRIGHTNESS_WARM_VALUE = onyx_max_screen_brightness_warm_value; 202 203 EINK_SCREEN_REGAL = onyx_support_regal; // TODO: add other e-ink devices with regal support 204 205 EINK_HAVE_FRONTLIGHT = ONYX_HAVE_FRONTLIGHT; // TODO: add other e-ink devices with frontlight support 206 EINK_HAVE_NATURAL_BACKLIGHT = ONYX_HAVE_NATURAL_BACKLIGHT; // TODO: add other e-ink devices with natural backlight support 207 208 POCKETBOOK = MODEL.toLowerCase().startsWith("pocketbook") || MODEL.toLowerCase().startsWith("obreey"); 209 210 NOOK_NAVIGATION_KEYS = EINK_NOOK; // TODO: add autodetect 211 SONY_NAVIGATION_KEYS = EINK_SONY; 212 EINK_SCREEN_UPDATE_MODES_SUPPORTED = EINK_SCREEN && ( EINK_NOOK || EINK_TOLINO || EINK_ONYX ); // TODO: add autodetect 213 FORCE_HC_THEME = EINK_SCREEN || MODEL.equalsIgnoreCase("pocketbook vision"); 214 USE_CUSTOM_TOAST = EINK_SCREEN; 215 NOFLIBUSTA = POCKETBOOK; 216 NAVIGATE_LEFTRIGHT = POCKETBOOK && DEVICE.startsWith("EP10"); 217 REVERT_LANDSCAPE_VOLUME_KEYS = POCKETBOOK && DEVICE.startsWith("EP5A"); 218 MIN_SCREEN_BRIGHTNESS_VALUE = getMinBrightness(AMOLED_SCREEN ? 2 : (getSDKLevel() >= ICE_CREAM_SANDWICH ? 8 : 16)); 219 //BUFFER_COLOR_FORMAT = getSDKLevel() >= HONEYCOMB ? android.graphics.Bitmap.Config.ARGB_8888 : android.graphics.Bitmap.Config.RGB_565; 220 //BUFFER_COLOR_FORMAT = android.graphics.Bitmap.Config.ARGB_8888; 221 BUFFER_COLOR_FORMAT = EINK_SCREEN || USE_OPENGL ? android.graphics.Bitmap.Config.ARGB_8888 : android.graphics.Bitmap.Config.RGB_565; 222 PIXEL_FORMAT = (DeviceInfo.BUFFER_COLOR_FORMAT == android.graphics.Bitmap.Config.RGB_565) ? PixelFormat.RGB_565 : PixelFormat.RGBA_8888; 223 224 DEF_FONT_FACE = getSDKLevel() >= ICE_CREAM_SANDWICH ? "Roboto" : "Droid Sans"; 225 226 USE_BITMAP_MEMORY_HACK = getSDKLevel() < ICE_CREAM_SANDWICH; 227 ONE_COLUMN_IN_LANDSCAPE = POCKETBOOK && DEVICE.endsWith("SURFPAD"); 228 DEF_FONT_SIZE = POCKETBOOK && DEVICE.endsWith("SURFPAD") ? 18 : null; 229 } 230 231 private static String getBuildField(String fieldName) { 232 233 try { 234 return (String)Build.class.getField(fieldName).get(null); 235 } catch (Exception e) { 236 Log.d("cr3", "Exception while trying to check Build." + fieldName); 237 return ""; 238 } 239 } 240 241 242 static { 243 Log.i("cr3", "DeviceInfo: MANUFACTURER=" + MANUFACTURER + ", MODEL=" + MODEL + ", DEVICE=" + DEVICE + ", PRODUCT=" + PRODUCT + ", BRAND=" + BRAND); 244 Log.i("cr3", "DeviceInfo: MIN_SCREEN_BRIGHTNESS_VALUE=" + MIN_SCREEN_BRIGHTNESS_VALUE + "; MAX_SCREEN_BRIGHTNESS_VALUE=" + MAX_SCREEN_BRIGHTNESS_VALUE + "; EINK_SCREEN=" + EINK_SCREEN + "; EINK_SCREEN_REGAL=" + EINK_SCREEN_REGAL + ", AMOLED_SCREEN=" + AMOLED_SCREEN + ", POCKETBOOK=" + POCKETBOOK); 245 } 246 247 // multiple patterns divided by |, * wildcard can be placed at beginning and/or end of pattern 248 // samples: "samsung", "p500|p510", "sgs*|sgh*" 249 private static boolean match(String value, String pattern) { 250 if (pattern == null || pattern.length() == 0 || "*".equals(pattern)) 251 return true; // matches any value 252 if (value == null || value.length() == 0) 253 return false; 254 value = value.toLowerCase(); 255 pattern = pattern.toLowerCase(); 256 String[] patterns = pattern.split("\\|"); 257 for (String p : patterns) { 258 boolean startingWildcard = false; 259 boolean endingWildcard = false; 260 if (p.startsWith("*")) { 261 startingWildcard = true; 262 p = p.substring(1); 263 } 264 if (p.endsWith("*")) { 265 endingWildcard = true; 266 p = p.substring(0, p.length()-1); 267 } 268 if (startingWildcard && endingWildcard) { 269 if (value.indexOf(p) < 0) 270 return false; 271 } else if (startingWildcard) { 272 if (!value.endsWith(p)) 273 return false; 274 } else if (endingWildcard) { 275 if (!value.startsWith(p)) 276 return false; 277 } else { 278 if (!value.equals(p)) 279 return false; 280 } 281 } 282 return true; 283 } 284 285 // delimited by ; 286 // "manufacturer;model;device;brand", "manufacturer;model;device" or "manufacturer;model" or "manufacturer" 287 private static boolean matchDevice(String pattern) { 288 String[] patterns = pattern.split(";"); 289 if (patterns.length >= 1) 290 if (!match(MANUFACTURER, patterns[0])) 291 return false; 292 if (patterns.length >= 2) 293 if (!match(MODEL, patterns[1])) 294 return false; 295 if (patterns.length >= 3) 296 if (!match(DEVICE, patterns[2])) 297 return false; 298 if (patterns.length >= 4) 299 if (!match(BRAND, patterns[3])) 300 return false; 301 return true; 302 } 303 304 // // TEST 305 // private static boolean testMatchDevice(String manufacturer, String model, String device, String pattern) { 306 // String[] patterns = pattern.split(";"); 307 // if (patterns.length >= 1) 308 // if (!match(manufacturer, patterns[0])) 309 // return false; 310 // if (patterns.length >= 2) 311 // if (!match(model, patterns[1])) 312 // return false; 313 // if (patterns.length >= 3) 314 // if (!match(device, patterns[2])) 315 // return false; 316 // Log.v("cr3", "matched : " + pattern + " == " + manufacturer + "," + model + "," + device); 317 // return true; 318 // } 319 // 320 // static { 321 // testMatchDevice("Archos", "A70S", "A70S", "Archos;A70S"); 322 // testMatchDevice("MegaMan", "A70S", "A70S", "mega*;A70*"); 323 // testMatchDevice("MegaMan", "A70", "A70S", "*man;A70*"); 324 // } 325 getMinBrightness(int defValue)326 private static int getMinBrightness(int defValue) { 327 try { 328 for (int i=0; i<MIN_SCREEN_BRIGHTNESS_DB.length - 1; i+=2) { 329 if (matchDevice(MIN_SCREEN_BRIGHTNESS_DB[i])) { 330 return Integer.valueOf(MIN_SCREEN_BRIGHTNESS_DB[i+1]); 331 } 332 } 333 } catch (NumberFormatException e) { 334 // ignore 335 } 336 return defValue; 337 } 338 339 } 340