/*
* $Id$
* This file is a part of the Arakhne Foundation Classes, http://www.arakhne.org/afc
*
* Copyright (c) 2000-2012 Stephane GALLAND.
* Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
* Universite de Technologie de Belfort-Montbeliard.
* Copyright (c) 2013-2016 The original authors, and other authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.arakhne.afc.vmutil;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Objects;
import java.util.UUID;
/**
* Wrapper to the Android functions.
* This class was introduced to avoid to kill the current
* JVM even if the native functions are unloadable.
* In this way, on operating system without the support
* for the native libs is still able to be run.
*
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
* @since 7.0
*/
class OperatingSystemAndroidWrapper extends AbstractOperatingSystemWrapper {
private static final String PREFS_FILE = "device_id.xml"; //$NON-NLS-1$
private static final String PREFS_DEVICE_ID = "device_id"; //$NON-NLS-1$
/** Construct a wrapper.
*/
OperatingSystemAndroidWrapper() {
//
}
private static Object getPreferences(Object context) {
assert context != null;
try {
final Method method = context.getClass().getMethod("getSharedPreferences", String.class, int.class); //$NON-NLS-1$
final Object prefs = method.invoke(context, PREFS_FILE, 0);
assert prefs != null;
return prefs;
} catch (Exception exception) {
return null;
}
}
private static String getSerialFromPreferences(Object prefs) {
try {
final Method method = prefs.getClass().getMethod("getString", String.class, String .class); //$NON-NLS-1$
final Object v = method.invoke(prefs, PREFS_DEVICE_ID, null);
final String label = Objects.toString(v, null);
if (label != null && !label.isEmpty()) {
return label;
}
} catch (Exception exception) {
//
}
return null;
}
private static String getAndroidID() {
try {
final Class<?> secureClass = Android.getSecureSettingsClass();
final Method getStringMethod = secureClass.getMethod("getString", //$NON-NLS-1$
Android.getContextResolverClass(), String.class);
final Field androidIdField = secureClass.getField("ANDROID_ID"); //$NON-NLS-1$
final Object androidId = androidIdField.get(null);
final Object v = getStringMethod.invoke(null, Android.getContextResolver(), androidId);
final String label = Objects.toString(v, null);
// Use the Android ID unless it's broken, in which case fallback on deviceId,
// unless it's not available, then fallback on the phone id.
if (label != null && !label.isEmpty() && !"9774d56d682e549c".equalsIgnoreCase(label)) { //$NON-NLS-1$
// The id above is known as the broken id on 2.2 devices.
return label;
}
} catch (Exception exception) {
//
}
return null;
}
private static String getDeviceID(Object context) {
try {
final Class<?> contextClass = context.getClass();
Method method = contextClass.getMethod("getSystemService", String.class); //$NON-NLS-1$
final Field field = contextClass.getField("TELEPHONY_SERVICE"); //$NON-NLS-1$
final Object telephonyManager = method.invoke(context, field.get(null));
if (telephonyManager != null) {
method = telephonyManager.getClass().getMethod("getDeviceId"); //$NON-NLS-1$
final Object v = method.invoke(telephonyManager);
final String label = Objects.toString(v, null);
if (label != null && !label.isEmpty()) {
return label;
}
}
} catch (Exception exception) {
//
}
return null;
}
private static String randomID(Object prefs) {
// Compute a random id and put it in the prefs.
try {
final String serial = UUID.randomUUID().toString();
Method method = prefs.getClass().getMethod("edit"); //$NON-NLS-1$
Object v = method.invoke(prefs);
method = v.getClass().getMethod("putString", String.class, String.class); //$NON-NLS-1$
v = method.invoke(v, PREFS_DEVICE_ID, serial);
method = v.getClass().getMethod("commit"); //$NON-NLS-1$
method.invoke(v);
return serial;
} catch (Exception exception) {
//
}
return null;
}
@SuppressWarnings("checkstyle:npathcomplexity")
@Override
public String getOSSerialNumber(boolean enableSuperUser, boolean enableGUI) {
final Object androidContext;
try {
androidContext = Android.getContext();
} catch (Throwable exception) {
return null;
}
if (androidContext != null) {
// Read the prefs
final Object prefs = getPreferences(androidContext);
if (prefs == null) {
return null;
}
String serial = getSerialFromPreferences(prefs);
if (serial != null) {
return serial;
}
serial = getAndroidID();
if (serial != null) {
return serial;
}
serial = getDeviceID(androidContext);
if (serial != null) {
return serial;
}
return randomID(prefs);
}
return null;
}
@Override
public String getOSUUID(boolean enableSuperUser, boolean enableGUI) {
final String serial = getOSSerialNumber(enableSuperUser, enableGUI);
if (serial != null) {
try {
return UUID.fromString(serial).toString();
} catch (Throwable exception) {
//
}
try {
return UUID.nameUUIDFromBytes(serial.getBytes()).toString();
} catch (Throwable exception) {
//
}
}
return null;
}
@Override
public OperatingSystemIdentificationType getIdentificationType() {
return OperatingSystemIdentificationType.OPERATING_SYSTEM;
}
}