Java tutorial
/* * The MIT License (MIT) * * Copyright 2014 Marco Lizza (marco.lizza@gmail.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package com.brainasylum.andruid; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.math.BigInteger; import java.security.SecureRandom; import java.util.UUID; import org.json.JSONException; import org.json.JSONObject; import android.content.Context; import android.content.SharedPreferences; import android.os.Environment; import android.os.Process; import android.util.Log; public class UniqueIdentifierManager { private final static String TAG = "IdentifierManager"; private final static String FILE_DIR = "Android"; private final static String FILE_NAME = "UniqueIdentifiers.json"; private final UniqueIdentifier _identifier; private String _udid = null; public UniqueIdentifierManager(UniqueIdentifier identifier) { _identifier = identifier; } public synchronized UUID getUdid(Context context) { if (_udid == null) { // we are using the shared-preferences as a "cache" to // store the current UDID. This value doesn't persist // across application uninstall, so we fall back to the // external storage. // we (re)serialized always in order to keep the // preferences and external storage synched. if ((_udid = getPreferencesUdid(context)) != null) { Log.d(TAG, "UDID from preferences: " + _udid); } else if ((_udid = getSdCardUdid(context)) != null) { Log.d(TAG, "UDID from sd-card: " + _udid); } if ((_udid = _identifier.getId(context)) != null) { Log.d(TAG, "UDID from instance: " + _udid); } else { _udid = getGeneratedUdid(); Log.d(TAG, "UDID auto-generated: " + _udid); } serializeUdid(context, _udid); Log.d(TAG, "UDID serialized"); } try { return UUID.nameUUIDFromBytes(_udid.getBytes("utf8")); } catch (UnsupportedEncodingException e) { clearUdid(context); return null; } } public synchronized void clearUdid(Context context) { // if permissions are granted, remove the identifier from // the storage bundle... if (canWriteExternalStorage(context)) { File file = new File(Environment.getExternalStorageDirectory() + "/" + FILE_DIR, FILE_NAME); if (file.exists()) { try { // FileInputStream fis = new FileInputStream(file); byte[] buffer = new byte[(int) file.length()]; fis.read(buffer); fis.close(); JSONObject root = new JSONObject(new String(buffer)); // String applicationName = context.getApplicationInfo().packageName; // if (root.has(applicationName)) { JSONObject values = root.getJSONObject(applicationName); if (values.has(_identifier.getKey())) { // remove the identifier value and if it's the // last one in the object remove the application // node itself values.remove(_identifier.getKey()); if (values.length() == 0) { root.remove(applicationName); } // FileOutputStream fos = new FileOutputStream(file); fos.write(root.toString().getBytes()); fos.close(); } } } catch (IOException e) { Log.e(TAG, "I/O error with file " + file.getAbsolutePath(), e); e.printStackTrace(); } catch (JSONException e) { Log.e(TAG, "JSON error with file " + file.getAbsolutePath(), e); e.printStackTrace(); } } } // ... then remove it from the shared preferences... SharedPreferences prefs = context.getSharedPreferences(_identifier.getTag(), Context.MODE_PRIVATE); prefs.edit().remove(_identifier.getKey()).commit(); // ... and clear the instance cached value. _udid = null; } private String getSdCardUdid(Context context) { if (canReadExternalStorage(context)) { File file = new File(Environment.getExternalStorageDirectory() + "/" + FILE_DIR, FILE_NAME); if (file.exists()) { try { // FileInputStream fis = new FileInputStream(file); byte[] buffer = new byte[(int) file.length()]; fis.read(buffer); fis.close(); JSONObject root = new JSONObject(new String(buffer)); // String applicationName = context.getApplicationInfo().packageName; // if (root.has(applicationName)) { JSONObject values = root.getJSONObject(applicationName); if (values.has(_identifier.getKey())) { return values.getString(_identifier.getKey()); } else { return null; } } } catch (IOException e) { Log.e(TAG, "I/O error with file " + file.getAbsolutePath(), e); e.printStackTrace(); } catch (JSONException e) { Log.e(TAG, "JSON error with file " + file.getAbsolutePath(), e); e.printStackTrace(); } } } return null; } private String getPreferencesUdid(Context context) { SharedPreferences prefs = context.getSharedPreferences(_identifier.getTag(), Context.MODE_PRIVATE); return prefs.getString(_identifier.getKey(), null); } private static String getGeneratedUdid() { SecureRandom secureRandom = new SecureRandom(); return new BigInteger(64, secureRandom).toString(16); } private static boolean canWriteExternalStorage(Context context) { return (context.checkPermission("android.permission.WRITE_EXTERNAL_STORAGE", Process.myPid(), Process.myUid()) == 0) && (isSdCardMounted()); } private static boolean canReadExternalStorage(Context context) { return (context.checkPermission("android.permission.READ_EXTERNAL_STORAGE", Process.myPid(), Process.myUid()) == 0) && ((isSdCardMountedReadOnly()) || (isSdCardMounted())); } private static boolean isSdCardMounted() { return "mounted".equals(Environment.getExternalStorageState()); } private static boolean isSdCardMountedReadOnly() { return "mounted_ro".equals(Environment.getExternalStorageState()); } private void serializeUdid(Context context, String udid) { // if the external storage is writable (according to the current // application manifest settings) write to file if (canWriteExternalStorage(context)) { File dir = new File(Environment.getExternalStorageDirectory() + "/" + FILE_DIR); if (!dir.exists()) { dir.mkdir(); } // File file = new File(dir, FILE_NAME); // String applicationName = context.getApplicationInfo().packageName; // try { // JSONObject root; if (file.exists()) { FileInputStream fis = new FileInputStream(file); byte[] buffer = new byte[(int) file.length()]; fis.read(buffer); fis.close(); root = new JSONObject(new String(buffer)); } else { root = new JSONObject(); } JSONObject values; if (root.has(applicationName)) { values = root.getJSONObject(applicationName); } else { values = new JSONObject(); root.put(applicationName, values); } // values.put(_identifier.getKey(), udid); // FileOutputStream fos = new FileOutputStream(file); fos.write(root.toString().getBytes()); fos.close(); } catch (JSONException e) { Log.e(TAG, "JSON error with file " + file.getAbsolutePath(), e); e.printStackTrace(); } catch (IOException e) { Log.e(TAG, "I/O error with file " + file.getAbsolutePath(), e); e.printStackTrace(); } } // ... then store the value in the preference file, too... SharedPreferences prefs = context.getSharedPreferences(_identifier.getTag(), Context.MODE_PRIVATE); prefs.edit().putString(_identifier.getKey(), udid.toString()).commit(); } }