1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.omadm.plugin.dev; 18 19import android.content.Context; 20import android.content.SharedPreferences; 21import android.database.Cursor; 22import android.database.sqlite.SQLiteDatabase; 23import android.net.wifi.WifiInfo; 24import android.net.wifi.WifiManager; 25import android.os.RemoteException; 26import android.os.SystemProperties; 27import android.provider.Settings; 28import android.provider.Settings.SettingNotFoundException; 29import android.telephony.TelephonyManager; 30import android.text.TextUtils; 31import android.util.Log; 32 33import com.android.omadm.plugin.DmtBasePlugin; 34import com.android.omadm.plugin.DmtData; 35import com.android.omadm.plugin.DmtException; 36import com.android.omadm.plugin.DmtPluginNode; 37import com.android.omadm.plugin.ErrorCodes; 38import com.android.omadm.service.DMSettingsHelper; 39 40import java.util.HashMap; 41import java.util.Locale; 42import java.util.Map; 43 44public class DevPlugin extends DmtBasePlugin { 45 46 static final String TAG = "DM_DevPlugin"; 47 48 private String mRootPath; 49 50 private Context mContext; 51 52 public static final String DEV_DETAIL = "devdetail"; 53 54 public static final String WIFI_MAC_ADDR = "wifimacaddr"; 55 56 public static final String PRE_FW_VER = "prefwversion"; 57 58 public static final String LAST_UPD_TIME = "lastupdatetime"; 59 60// public static final Uri DMFLEXS_CONTENT_URI = Uri 61// .parse("content://com.android.omadm.service/flexs"); 62 63 public DevPlugin(Context ctx) { 64 mContext = ctx; 65 } 66 67 @Override 68 @SuppressWarnings({"unchecked", "rawtypes"}) 69 public boolean init(String rootPath, Map parameters) { 70 logd("Enter DevPlugin.init(\"" + rootPath + "\", " + parameters + "\")"); 71 mRootPath = rootPath; 72 return true; 73 } 74 75 @Override 76 public DmtPluginNode getNode(String path) { 77 logd("getNode(\"" + path + "\")"); 78 DmtPluginNode node = new DmtPluginNode("", new DmtData("abc")); 79 setOperationResult(node == null ? 80 ErrorCodes.SYNCML_DM_FAIL : 81 ErrorCodes.SYNCML_DM_SUCCESS); 82 return node; 83 } 84 85 @Override 86 public DmtData getNodeValue(String path) { 87 logd("getNodeValue: rootPath=" + mRootPath + " path=" + path); 88 89 //mContext.enforceCallingPermission("com.android.permission.READ_OMADM_SETTINGS", "Insufficient Permissions"); 90 DmtData data = null; 91 92 if (path.equals("./DevDetail/SwV") || path.equals("./DevDetail/FwV")) { 93 String SwV; 94 try { 95 if (!isSprint() && path.equals("./DevDetail/SwV")) { 96 SwV = "Android " + SystemProperties.get("ro.build.version.release"); 97 } else { 98 SwV = SystemProperties.get("ro.build.version.full"); 99 if (null == SwV || SwV.equals("")) { 100 SwV = SystemProperties.get("ro.build.id", null) + "~" 101 + SystemProperties.get("ro.build.config.version", null) + "~" 102 + SystemProperties.get("gsm.version.baseband", null) + "~" 103 + SystemProperties.get("ro.gsm.flexversion", null); 104 } 105 } 106 } catch (RuntimeException e) { 107 SwV = "Unknown"; 108 } 109 data = new DmtData(SwV); 110 } else if ("./DevDetail/HwV".equals(path)) { 111 String HwV; 112 try { 113 HwV = SystemProperties.get("ro.hardware", "Unknown") 114 + "." + SystemProperties.get("ro.revision", "Unknown"); 115 } catch (RuntimeException e) { 116 HwV = "Unknown"; 117 } 118 logd("get ./DevDetail/HwV = " + HwV); 119 data = new DmtData(HwV); 120 } else if ("./DevDetail/DevTyp".equals(path)) { 121 String DevTyp = getDeviceType(); 122 logd("get ./DevDetail/DevTyp = " + DevTyp); 123 data = new DmtData(DevTyp); 124 } else if ("./DevInfo/DevId".equals(path)) { 125 TelephonyManager tm = (TelephonyManager) mContext 126 .getSystemService(Context.TELEPHONY_SERVICE); 127 String simOperator = tm.getSimOperator(); 128 String imsi = tm.getSubscriberId(); 129 logd("simOperator: " + simOperator + " IMSI: " + imsi); 130 /* Use MEID for sprint */ 131 if ("310120".equals(simOperator) || (imsi != null && imsi.startsWith("310120"))) { 132 /* MEID is 14 digits. If IMEI is returned as DevId, MEID can be extracted by taking 133 * first 14 characters. This is not always true but should be the case for sprint */ 134 String strDevId = tm.getDeviceId(); 135 strDevId = strDevId.toUpperCase(Locale.US); 136 logd("DeviceId from telemgr: " + strDevId); 137 if (strDevId != null && strDevId.length() >= 14) { 138 strDevId = strDevId.substring(0, 14); 139 logd("MEID (from DeviceId): " + strDevId); 140 data = new DmtData("MEID:" + strDevId); 141 } else { 142 loge("MEID cannot be extracted from DeviceId " + strDevId); 143 } 144 } else { 145 String strDevId; 146 if (isPhoneTypeLTE()) { 147 strDevId = tm.getImei(); 148 } else { 149 strDevId = tm.getDeviceId(); 150 } 151 strDevId = strDevId.toUpperCase(Locale.US); 152 logd("DevId from telemgr: " + strDevId); 153 154 if (isPhoneTypeLTE()) { 155 data = new DmtData("IMEI:" + strDevId); 156 } else { 157 data = new DmtData("MEID:" + strDevId.substring(0, 14)); 158 } 159 } 160 } else if (path.equals("./DevInfo/DmV")) { 161 data = new DmtData("1.2"); 162 } else if (path.equals("./DevInfo/Lang")) { 163 String strLang = readValueFromFile("Lang"); 164 logd("Language from shared file:" + strLang); 165 if (strLang == null) { 166 strLang = Locale.getDefault().toString(); 167 logd("Language from system is:" + strLang); 168 } 169 data = new DmtData(strLang); 170 } else if (path.equals("./DevInfo/Man")) { 171 String strMan = readValueFromFile("Man"); 172 logd("Manufacturer got from shared file:" + strMan); 173 if (strMan == null) { 174 strMan = SystemProperties.get("ro.product.manufacturer", "unknown"); 175 logd("Manufacturer from system properties:" + strMan); 176 } 177 data = new DmtData(strMan.toLowerCase(Locale.US)); 178 } else if (path.equals("./DevInfo/Mod")) { 179 String strMod = readValueFromFile("Mod"); 180 logd("Mod got from shared file:" + strMod); 181 if (strMod == null) { 182 strMod = SystemProperties.get("ro.product.model", "generic"); 183 logd("Mod got from system properties:" + strMod); 184 } 185 data = new DmtData(strMod); 186 } else if (path.equals("./DevDetail/Bearer/GSM")) { 187 data = new DmtData("GSM_1900"); 188 } else if (path.equals("./DevDetail/Bearer/CDMA")) { 189 data = new DmtData("CDMA_2000"); 190 } else if (path.equals("./DevDetail/Ext/SystemSettings/AllowUnknownSources")) { 191 if (!isThisForATT()) { 192 logd("Not Supported for non ATT carriers"); 193 data = new DmtData("Not Supported"); 194 } else { 195 boolean mUnknownSources = false; 196 197 try { 198 if (Settings.Global.getInt(mContext.getContentResolver(), 199 Settings.Global.INSTALL_NON_MARKET_APPS) > 0) { 200 logd("install from non-market -- allowed"); 201 mUnknownSources = true; 202 data = new DmtData(mUnknownSources); 203 } else { 204 logd("install from non-market -- not allowed"); 205 mUnknownSources = false; 206 data = new DmtData(mUnknownSources); 207 } 208 } catch (SettingNotFoundException e) { 209 loge("Exception while reading Settings.Global.INSTALL_NON_MARKET_APPS", e); 210 } 211 } 212 } else if (path.equals("./DevDetail/Ext/WLANMacAddr")) { 213 if (!isThisForATT()) { 214 logd("Not Supported for non ATT carriers"); 215 data = new DmtData("Not Supported"); 216 } else { 217 String wMac = ""; 218 SharedPreferences p = mContext.getSharedPreferences(DEV_DETAIL, 0); 219 220 if (p.contains(WIFI_MAC_ADDR)) { 221 wMac = p.getString(DevPlugin.WIFI_MAC_ADDR, null); 222 logd("Read WiFi Mac address from shared file: " + wMac); 223 data = new DmtData(wMac); 224 } else { 225 WifiManager wm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); 226 WifiInfo wi = wm.getConnectionInfo(); 227 wMac = wi == null ? null : wi.getMacAddress(); 228 logd("WiFi Mac address" + wMac); 229 if (!TextUtils.isEmpty(wMac)) { 230 SharedPreferences.Editor ed = p.edit(); 231 ed.putString(DevPlugin.WIFI_MAC_ADDR, wMac); 232 ed.apply(); 233 234 data = new DmtData(wMac); 235 } else { 236 data = new DmtData("Unavailable"); 237 } 238 } 239 } 240 } else if (path.equals("./DevDetail/Ext/PreFwV")) { 241 if (!isThisForATT()) { 242 logd("Not Supported for non ATT carriers"); 243 data = new DmtData("Not Supported"); 244 } else { 245 String preFwV = ""; 246 SharedPreferences p = mContext.getSharedPreferences(DEV_DETAIL, 0); 247 248 if (p.contains(PRE_FW_VER)) { 249 preFwV = p.getString(DevPlugin.PRE_FW_VER, null); 250 logd("Read Previous Firmware Version from shared file" + preFwV); 251 data = new DmtData(preFwV); 252 } else { 253 String SwV; 254 try { 255 SwV = SystemProperties.get("ro.build.version.full"); 256 } catch (Exception e) { 257 SwV = "Unknown"; 258 } 259 data = new DmtData(SwV); 260 } 261 } 262 } else if (path.equals("./DevDetail/Ext/LastUpdateTime")) { 263 if (!isThisForATT()) { 264 logd("Not Supported for non ATT carriers"); 265 data = new DmtData("Not Supported"); 266 } else { 267 String lastUpd = ""; 268 SharedPreferences p = mContext.getSharedPreferences(DevPlugin.DEV_DETAIL, 0); 269 270 if (p.contains(LAST_UPD_TIME)) { 271 lastUpd = p.getString(DevPlugin.LAST_UPD_TIME, null); 272 logd("Read date stamp for the last update from shared file: " + lastUpd); 273 data = new DmtData(lastUpd); 274 } else { 275 data = new DmtData("No Known Update"); 276 } 277 } 278 } else if (path.equals("./DevDetail/Ext/DateTime/Date")) { 279 if (!isPhoneTypeLTE()) { 280 logd("Not Supported for non VZW carriers"); 281 data = new DmtData("Not Supported"); 282 } else { 283 String updateDateTime = ""; 284 SharedPreferences p = mContext.getSharedPreferences(DevPlugin.DEV_DETAIL, 0); 285 286 if (p.contains(LAST_UPD_TIME)) { 287 updateDateTime = p.getString(DevPlugin.LAST_UPD_TIME, null); 288 logd("Read date and time stamp for the last update from shared file: " 289 + updateDateTime); 290 String[] updateDate = updateDateTime.split("\\:"); 291 try { 292 data = new DmtData( 293 updateDate[0] + ":" + updateDate[1] + ":" + updateDate[2]); 294 } catch (Exception e) { 295 data = new DmtData("No Known Update"); 296 e.printStackTrace(); 297 } 298 } else { 299 data = new DmtData("No Known Update"); 300 } 301 } 302 } else if (path.equals("./DevDetail/Ext/DateTime/TimeUTC")) { 303 if (!isPhoneTypeLTE()) { 304 logd("Not Supported for non VZW carriers"); 305 data = new DmtData("Not Supported"); 306 } else { 307 String updateDateTime = ""; 308 SharedPreferences p = mContext.getSharedPreferences(DevPlugin.DEV_DETAIL, 0); 309 310 if (p.contains(LAST_UPD_TIME)) { 311 updateDateTime = p.getString(DevPlugin.LAST_UPD_TIME, null); 312 logd("Read date and time stamp for the last update from shared file: " 313 + updateDateTime); 314 String[] updateTime = updateDateTime.split("\\:"); 315 try { 316 data = new DmtData(updateTime[3] + ":" + updateTime[4]); 317 } catch (Exception e) { 318 data = new DmtData("No Known Update"); 319 e.printStackTrace(); 320 } 321 } else { 322 data = new DmtData("No Known Update"); 323 } 324 } 325 } else if (path.equals("./DevDetail/Ext/DateTime/DLS")) { 326 setOperationResult(ErrorCodes.SYNCML_DM_UNSUPPORTED_OPERATION); 327 } 328 329 setOperationResult(data == null ? 330 ErrorCodes.SYNCML_DM_UNSUPPORTED_OPERATION : 331 ErrorCodes.SYNCML_DM_SUCCESS); 332 333 return data; 334 } 335 336 @Override 337 public int updateLeafNode(String path, DmtData newValue) throws RemoteException { 338 logd("updateLeafNode: rootPath=" + mRootPath + " path=" + path + " newValue=" + newValue); 339 //mContext.enforceCallingPermission("com.android.permission.WRITE_OMADM_SETTINGS", "Insufficient Permissions"); 340 341 if (path.equals("./DevDetail/Ext/SystemSettings/AllowUnknownSources")) { 342 if (!isThisForATT()) { 343 logd("Not Supported for non ATT carriers"); 344 return setOperationResult(ErrorCodes.SYNCML_DM_UNSUPPORTED_OPERATION); 345 } else { 346 // enable/disable install from non market 347 try { 348 Settings.Global.putInt(mContext.getContentResolver(), 349 Settings.Global.INSTALL_NON_MARKET_APPS, 350 ((newValue.getBoolean()) ? 1 : 0)); 351 if ((Settings.Global.getInt(mContext.getContentResolver(), 352 Settings.Global.INSTALL_NON_MARKET_APPS)) 353 == (newValue.getBoolean() ? 1 : 0)) { 354 logd("Update to settings.db for install_non_market_apps -- success"); 355 return setOperationResult(ErrorCodes.SYNCML_DM_SUCCESS); 356 } else { 357 logd("Update to settings.db for install_non_market_apps -- failed"); 358 return setOperationResult(ErrorCodes.SYNCML_DM_FAIL); 359 } 360 } catch (DmtException e) { 361 loge("Exception during parsing the newValue.getBoolean()", e); 362 return setOperationResult(ErrorCodes.SYNCML_DM_FAIL); 363 } catch (SettingNotFoundException e) { 364 loge("Exception retrieving Settings.Global.INSTALL_NON_MARKET_APPS", e); 365 return setOperationResult(ErrorCodes.SYNCML_DM_FAIL); 366 } 367 } 368 } else { 369 return setOperationResult(ErrorCodes.SYNCML_DM_FAIL); 370 } 371 } 372 373 @SuppressWarnings("unchecked") 374 @Override 375 public Map getNodes(String rootPath) { 376 logd("Enter DevPlugin.getNodes(\"" + rootPath + "\")"); 377 Map<String, DmtPluginNode> hMap = new HashMap<String, DmtPluginNode>(); 378 DmtPluginNode node1; 379 node1 = new DmtPluginNode("", new DmtData("abc")); 380 hMap.put("", node1); 381 logd("Leave DevPlugin::getNodes()"); 382 return hMap; 383 } 384 385 public boolean release() { 386 return true; 387 } 388 389 private String readValueFromFile(String propName) { 390 String ret = null; 391 // use preference instead of the system property 392 SharedPreferences prefs = mContext.getSharedPreferences("dmconfig", 0); 393 if (prefs.contains(propName)) { 394 ret = prefs.getString(propName, ""); 395 if (ret.length() == 0) { 396 ret = null; 397 } 398 } 399 return ret; 400 } 401 402 private boolean isThisForATT() { 403 boolean carrierATT = false; 404 Cursor cr = null; 405 try { 406 String DATABASE_NAME = "DmConfigure.db"; 407 SQLiteDatabase mdb = mContext.openOrCreateDatabase(DATABASE_NAME, 0, null); 408 cr = mdb.query("dmFlexs", null, "name='CarrierName'", null, null, null, null); 409 String value = null; 410 411 if (cr != null) { 412 if (cr.moveToFirst() == true) { 413 int index = cr.getColumnIndex("value"); 414 value = cr.getString(index); 415 logd("CarrierName = " + value); 416 } 417 if ("ATT".equals(value) || "Att".equals(value) || "att".equals(value)) { 418 carrierATT = true; 419 } 420 } 421 422 } catch (Exception e) { 423 loge("Not able to get CarrierName from database, return false", e); 424 } finally { 425 if (cr != null) { 426 cr.close(); 427 } 428 } 429 return carrierATT; 430 } 431 432 private boolean isPhoneTypeLTE() { 433 return DMSettingsHelper.isPhoneTypeLTE(); 434 } 435 436 private String getDeviceType() { 437 String devicetype = SystemProperties.get("ro.build.characteristics"); 438 if (((!TextUtils.isEmpty(devicetype)) && (devicetype.equals("tablet")))) { 439 logd("Device Type is Tablet"); 440 } else { 441 devicetype = "phone"; 442 logd("Device Type is Phone"); 443 } 444 return devicetype; 445 } 446 447 private static void logd(String s) { 448 Log.d(TAG, s); 449 } 450 451 private static void loge(String s) { 452 Log.e(TAG, s); 453 } 454 455 private static void loge(String s, Throwable tr) { 456 Log.e(TAG, s, tr); 457 } 458 459 private boolean isSprint() { 460 TelephonyManager tm = (TelephonyManager) mContext 461 .getSystemService(Context.TELEPHONY_SERVICE); 462 String simOperator = tm.getSimOperator(); 463 String imsi = tm.getSubscriberId(); 464 logd("simOperator: " + simOperator + " IMSI: " + imsi); 465 /* Use MEID for sprint */ 466 if ("310120".equals(simOperator) || (imsi != null && imsi.startsWith("310120"))) { 467 return true; 468 } else { 469 return false; 470 } 471 } 472} 473