13a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank/*
23a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank /*
33a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank * Copyright (C) 2011 The Android Open Source Project
43a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank *
53a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank * Licensed under the Apache License, Version 2.0 (the "License");
63a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank * you may not use this file except in compliance with the License.
73a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank * You may obtain a copy of the License at
83a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank *
93a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank *      http://www.apache.org/licenses/LICENSE-2.0
103a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank *
113a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank * Unless required by applicable law or agreed to in writing, software
123a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank * distributed under the License is distributed on an "AS IS" BASIS,
133a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
143a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank * See the License for the specific language governing permissions and
153a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank * limitations under the License.
163a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank */
173a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank
183a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blankpackage com.android.emailcommon;
193a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank
203a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blankimport android.content.Context;
213a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blankimport android.telephony.TelephonyManager;
223a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank
23a9f1631fb83200a59e40e23ed366f810d08b6f52Marc Blankimport com.android.emailcommon.utility.Utility;
24560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedyimport com.android.mail.utils.LogUtils;
25a9f1631fb83200a59e40e23ed366f810d08b6f52Marc Blank
263a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blankimport java.io.BufferedReader;
273a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blankimport java.io.BufferedWriter;
283a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blankimport java.io.File;
293a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blankimport java.io.FileReader;
303a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blankimport java.io.FileWriter;
313a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blankimport java.io.IOException;
323a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank
333a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blankpublic class Device {
343a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank    private static String sDeviceId = null;
353a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank
363a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank    /**
373a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank     * EAS requires a unique device id, so that sync is possible from a variety of different
383a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank     * devices (e.g. the syncKey is specific to a device)  If we're on an emulator or some other
393a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank     * device that doesn't provide one, we can create it as android<n> where <n> is system time.
403a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank     * This would work on a real device as well, but it would be better to use the "real" id if
413a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank     * it's available
423a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank     */
433a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank    static public synchronized String getDeviceId(Context context) throws IOException {
443a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        if (sDeviceId == null) {
453a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank            sDeviceId = getDeviceIdInternal(context);
463a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        }
473a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        return sDeviceId;
483a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank    }
493a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank
503a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank    static private String getDeviceIdInternal(Context context) throws IOException {
513a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        if (context == null) {
523a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank            throw new IllegalStateException("getDeviceId requires a Context");
533a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        }
543a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        File f = context.getFileStreamPath("deviceName");
553a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        BufferedReader rdr = null;
563a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        String id;
573a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        if (f.exists()) {
583a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank            if (f.canRead()) {
593a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank                rdr = new BufferedReader(new FileReader(f), 128);
603a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank                id = rdr.readLine();
613a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank                rdr.close();
62a6de89e79ca51535f92e38cd7b87fdfe32425c77Marc Blank                if (id == null) {
63a6de89e79ca51535f92e38cd7b87fdfe32425c77Marc Blank                    // It's very bad if we read a null device id; let's delete that file
64a6de89e79ca51535f92e38cd7b87fdfe32425c77Marc Blank                    if (!f.delete()) {
65560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy                        LogUtils.e(Logging.LOG_TAG,
66560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy                                "Can't delete null deviceName file; try overwrite.");
67a6de89e79ca51535f92e38cd7b87fdfe32425c77Marc Blank                    }
68185fd5b3b8251858f0cfad0c180eefebcb38b801Marc Blank                } else {
69185fd5b3b8251858f0cfad0c180eefebcb38b801Marc Blank                    return id;
70a6de89e79ca51535f92e38cd7b87fdfe32425c77Marc Blank                }
713a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank            } else {
72560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy                LogUtils.w(Logging.LOG_TAG, f.getAbsolutePath() + ": File exists, but can't read?" +
733a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank                    "  Trying to remove.");
743a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank                if (!f.delete()) {
75560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy                    LogUtils.w(Logging.LOG_TAG, "Remove failed. Tring to overwrite.");
763a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank                }
773a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank            }
783a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        }
793a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        BufferedWriter w = new BufferedWriter(new FileWriter(f), 128);
803a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        final String consistentDeviceId = getConsistentDeviceId(context);
813a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        if (consistentDeviceId != null) {
823a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank            // Use different prefix from random IDs.
833a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank            id = "androidc" + consistentDeviceId;
843a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        } else {
853a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank            id = "android" + System.currentTimeMillis();
863a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        }
873a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        w.write(id);
883a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        w.close();
893a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        return id;
903a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank    }
913a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank
923a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank    /**
933a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank     * @return Device's unique ID if available.  null if the device has no unique ID.
943a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank     */
953a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank    public static String getConsistentDeviceId(Context context) {
963a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        final String deviceId;
973a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        try {
983a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank            TelephonyManager tm =
993a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank                (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
1003a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank            if (tm == null) {
1013a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank                return null;
1023a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank            }
1033a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank            deviceId = tm.getDeviceId();
1043a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank            if (deviceId == null) {
1053a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank                return null;
1063a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank            }
1073a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        } catch (Exception e) {
108560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy            LogUtils.d(Logging.LOG_TAG, "Error in TelephonyManager.getDeviceId(): "
109560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy                    + e.getMessage());
1103a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank            return null;
1113a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        }
1123a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        return Utility.getSmallHash(deviceId);
1133a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank    }
1143a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank}
115