Device.java revision a9f1631fb83200a59e40e23ed366f810d08b6f52
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 Blankimport android.util.Log;
233a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank
24a9f1631fb83200a59e40e23ed366f810d08b6f52Marc Blankimport com.android.emailcommon.utility.Utility;
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()) {
65a6de89e79ca51535f92e38cd7b87fdfe32425c77Marc Blank                        Log.e(Logging.LOG_TAG, "Can't delete null deviceName file; try overwrite.");
66a6de89e79ca51535f92e38cd7b87fdfe32425c77Marc Blank                    }
67a6de89e79ca51535f92e38cd7b87fdfe32425c77Marc Blank                }
683a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank            } else {
693a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank                Log.w(Logging.LOG_TAG, f.getAbsolutePath() + ": File exists, but can't read?" +
703a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank                    "  Trying to remove.");
713a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank                if (!f.delete()) {
723a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank                    Log.w(Logging.LOG_TAG, "Remove failed. Tring to overwrite.");
733a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank                }
743a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank            }
753a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        }
763a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        BufferedWriter w = new BufferedWriter(new FileWriter(f), 128);
773a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        final String consistentDeviceId = getConsistentDeviceId(context);
783a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        if (consistentDeviceId != null) {
793a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank            // Use different prefix from random IDs.
803a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank            id = "androidc" + consistentDeviceId;
813a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        } else {
823a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank            id = "android" + System.currentTimeMillis();
833a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        }
843a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        w.write(id);
853a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        w.close();
863a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        return id;
873a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank    }
883a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank
893a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank    /**
903a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank     * @return Device's unique ID if available.  null if the device has no unique ID.
913a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank     */
923a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank    public static String getConsistentDeviceId(Context context) {
933a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        final String deviceId;
943a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        try {
953a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank            TelephonyManager tm =
963a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank                (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
973a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank            if (tm == null) {
983a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank                return null;
993a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank            }
1003a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank            deviceId = tm.getDeviceId();
1013a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank            if (deviceId == null) {
1023a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank                return null;
1033a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank            }
1043a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        } catch (Exception e) {
1053a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank            Log.d(Logging.LOG_TAG, "Error in TelephonyManager.getDeviceId(): " + e.getMessage());
1063a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank            return null;
1073a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        }
1083a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank        return Utility.getSmallHash(deviceId);
1093a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank    }
1103a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank}
111