Skip to content

Instantly share code, notes, and snippets.

@Cheesebaron
Last active August 29, 2015 14:26
Show Gist options
  • Save Cheesebaron/33d5fca0efd0eb3a237a to your computer and use it in GitHub Desktop.
Save Cheesebaron/33d5fca0efd0eb3a237a to your computer and use it in GitHub Desktop.
Year classification for Android. Based on Facebook's device-year-class: https://github.com/facebook/device-year-class
using System;
using System.IO;
using System.Linq;
using Android.OS;
using Android.Util;
namespace DeviceYearClass
{
public class DeviceInfo
{
public const int DeviceInfoUnknown = -1;
private static readonly object LockCpu = new object();
private static readonly object LockFreq = new object();
private static readonly object LockMem = new object();
public static int NumberOfCpuCores
{
get
{
lock (LockCpu)
{
if (Build.VERSION.SdkInt <= BuildVersionCodes.GingerbreadMr1)
return 1;
var directories = Directory.GetDirectories("/sys/devices/system/cpu/");
try
{
var cores =
directories.Where(file => file.StartsWith("/sys/devices/system/cpu/cpu"))
.Count(
file => file.Substring(27).All(char.IsNumber));
return cores;
}
catch (Exception ex)
{
Log.Debug("DeviceInfo", "GetNumberOfCpuCores failed with exception: {0}", ex);
return DeviceInfoUnknown;
}
}
}
}
public static int GetCpuMaxFreqKHz
{
get
{
lock (LockFreq)
{
var maxFreq = DeviceInfoUnknown;
try
{
for (var i = 0; i < NumberOfCpuCores; i++)
{
var fileName = "/sys/devices/system/cpu/cpu" + i +
"/cpufreq/cpuinfo_max_freq";
if (!File.Exists(fileName)) continue;
var lines = File.ReadAllLines(fileName);
maxFreq = lines.Select(int.Parse).Concat(new[] {maxFreq}).Max();
}
}
catch (FormatException)
{
// fall through to /proc/cpuinfo
}
try
{
if (maxFreq == DeviceInfoUnknown)
{
var lines = File.ReadAllLines("/proc/cpuinfo");
foreach (
var freq in
lines.Where(line => line.ToLower().StartsWith("cpu mhz")).Select(
line =>
new string(line.Where(c => c >= '0' && c <= '9').ToArray()))
.Select(
int.Parse).Where(freq => freq > maxFreq))
{
maxFreq = (freq*1000);
}
}
}
catch (FormatException)
{
maxFreq = DeviceInfoUnknown;
}
return maxFreq;
}
}
}
public static long TotalMemory
{
get
{
lock (LockMem)
{
long totalMem = DeviceInfoUnknown;
try
{
var lines = File.ReadAllLines("/proc/meminfo");
foreach (var mem in from line in lines
where line.ToLower().StartsWith("memtotal")
select new string(line.Where(c => c >= '0' && c <= '9').ToArray())
into memStr
select long.Parse(memStr))
{
totalMem = mem*1024L;
}
}
catch (FormatException) {}
return totalMem;
}
}
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<TextView
android:id="@+id/numberOfCpusLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Number of CPUs"
android:textStyle="bold" />
<TextView
android:id="@+id/numberOfCpus"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="N/A" />
<TextView
android:id="@+id/cpuMaxFreqLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="CPU Max Frequency"
android:textStyle="bold" />
<TextView
android:id="@+id/cpuMaxFreq"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="N/A" />
<TextView
android:id="@+id/totalMemLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Total Memory"
android:textStyle="bold" />
<TextView
android:id="@+id/totalMem"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="N/A" />
<TextView
android:id="@+id/numCoresYearLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Number of Cores Year"
android:textStyle="bold" />
<TextView
android:id="@+id/numCoresYear"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="N/A" />
<TextView
android:id="@+id/clockSpeedYearLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Clock Speed Year"
android:textStyle="bold" />
<TextView
android:id="@+id/clockSpeedYear"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="N/A" />
<TextView
android:id="@+id/memoryYearLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Memory Year"
android:textStyle="bold" />
<TextView
android:id="@+id/memoryYear"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="N/A" />
<TextView
android:id="@+id/overallYearLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Overall Year"
android:textStyle="bold" />
<TextView
android:id="@+id/overallYear"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="N/A" />
</LinearLayout>
using Android.App;
using Android.OS;
using Android.Widget;
using DeviceYearClass;
namespace Sample
{
[Activity(Label = "Sample", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
var cpuCores = FindViewById<TextView>(Resource.Id.numberOfCpus);
cpuCores.Text = "" + DeviceInfo.NumberOfCpuCores;
var maxFreq = FindViewById<TextView>(Resource.Id.cpuMaxFreq);
maxFreq.Text = string.Format("{0} kHz", DeviceInfo.GetCpuMaxFreqKHz);
var totalMem = FindViewById<TextView>(Resource.Id.totalMem);
totalMem.Text = string.Format("{0} Bytes", DeviceInfo.TotalMemory);
var cpuCoresYear = FindViewById<TextView>(Resource.Id.numCoresYear);
cpuCoresYear.Text = string.Format("{0}", YearClass.NumberOfCoresYear);
var clockSpeedYear = FindViewById<TextView>(Resource.Id.clockSpeedYear);
clockSpeedYear.Text = string.Format("{0}", YearClass.ClockSpeedYear);
var memoryYear = FindViewById<TextView>(Resource.Id.memoryYear);
memoryYear.Text = string.Format("{0}", YearClass.RamYear);
var overallYear = FindViewById<TextView>(Resource.Id.overallYear);
overallYear.Text = string.Format("{0}", YearClass.Year);
}
}
}
using System.Collections.Generic;
using System.Linq;
using Android.Util;
namespace DeviceYearClass
{
public class YearClass
{
private const long Mb = 1024*1024;
private const int MhzInKhz = 1000;
public const int ClassUnknown = -1;
public const int Class2008 = 2008;
public const int Class2009 = 2009;
public const int Class2010 = 2010;
public const int Class2011 = 2011;
public const int Class2012 = 2012;
public const int Class2013 = 2013;
public const int Class2014 = 2014;
private static int _yearCategory = ClassUnknown;
public static int Year
{
get
{
if (_yearCategory == ClassUnknown)
{
var componentYears = new List<int>();
ConditionallyAdd(componentYears, NumberOfCoresYear);
ConditionallyAdd(componentYears, ClockSpeedYear);
ConditionallyAdd(componentYears, RamYear);
if (!componentYears.Any())
return ClassUnknown;
componentYears.Sort();
if ((componentYears.Count & 0x01) == 1) // Odd number; pluck the median.
{
_yearCategory = componentYears[componentYears.Count / 2];
Log.Debug("YearClass", "Odd number: {0}", _yearCategory);
return _yearCategory;
}
// Even number, Average the two "center" values.
var baseIndex = componentYears.Count/2 - 1;
_yearCategory = componentYears[baseIndex] +
(componentYears[baseIndex + 1] - componentYears[baseIndex])/2;
Log.Debug("YearClass", "Even number: {0}", _yearCategory);
}
return _yearCategory;
}
}
private static void ConditionallyAdd(ICollection<int> list, int value)
{
if (value != ClassUnknown)
list.Add(value);
}
public static int NumberOfCoresYear
{
get
{
var cores = DeviceInfo.NumberOfCpuCores;
if (cores < 1) return ClassUnknown;
if (cores == 1) return Class2008;
if (cores <= 3) return Class2011;
return Class2012;
}
}
public static int ClockSpeedYear
{
get
{
var clockSpeedKHz = DeviceInfo.GetCpuMaxFreqKHz;
if (clockSpeedKHz == DeviceInfo.DeviceInfoUnknown) return ClassUnknown;
if (clockSpeedKHz <= 528 * MhzInKhz) return Class2008;
if (clockSpeedKHz <= 620 * MhzInKhz) return Class2009;
if (clockSpeedKHz <= 1020 * MhzInKhz) return Class2010;
if (clockSpeedKHz <= 1220* MhzInKhz) return Class2011;
if (clockSpeedKHz <= 1520* MhzInKhz) return Class2012;
if (clockSpeedKHz <= 2020 * MhzInKhz) return Class2013;
return Class2014;
}
}
public static int RamYear
{
get
{
var totalRam = DeviceInfo.TotalMemory;
if (totalRam <= 0) return ClassUnknown;
if (totalRam <= 192 * Mb) return Class2008;
if (totalRam <= 290 * Mb) return Class2009;
if (totalRam <= 512 * Mb) return Class2010;
if (totalRam <= 1024 * Mb) return Class2011;
if (totalRam <= 1536 * Mb) return Class2012;
if (totalRam <= 2048 * Mb) return Class2013;
return Class2014;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment