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