Музика для бабусі від онука-програміста

Моя бабуся з юності звикла слухати радіо, але, на жаль, зараз по радіо можна почути далеко не кращі композиції і передачі. Радіо можна замінити улюбленою музикою, але, на жаль, у моєї бабусі складності в звикання до техніки.
Найкращий подарунок — подарунок, зроблений своїми руками, тому я, як люблячий онук і програміст під мобільні платформи, заходився думати, як забезпечити бабусі простий доступ до її улюбленої музики.
 
Відразу скажу, що успіху я досяг, а от тим, кому цікавий процес — прошу під кат.
 
 main
 
 

Завдання

Для початку я намітив цілі, які хотів досягти:
 - Необхідно написати додаток, яке мало б два режими: грати музику і слухати радіо;
 - Інтерфейс програми повинен бути максимально простим;
 - Програма має працювати з картою пам'яті, щоб можна було легко замінювати джерело музики;
 - Додаток не повинно гасити екран, якщо тільки не натиснута клавіша блокування;
 - Якщо ми виходимо з програми, музика вимикається;
 - Додаток в процесі програвання аудіо має показувати дату, час і слайд-шоу з фото.
 
 

Вибір заліза

Необхідно було вибрати три речі: аудіо-колонку, підставку для смартфона і сам смартфон.
Тут, забігаючи вперед, скажу, що вибір мій вельми спірний: можна було придбати інші моделі з іншими характеристиками і ціною. Але як вийшло, так вийшло.
Спочатку хотілося, щоб смартфон був пов'язаний з колонкою по Bluetooth, т.к. чим менше проводів буде у бабусі, тим краще. Тому була обрана колонка Nokia MD-50W : вона досить гучна, має вбудований акумулятор, стандартний micro-USB роз'єм зарядки, Bluetooth і навіть NFC.
 
Смартфон було вирішено вибирати на платформі Windows Phone, т.к. по-перше, під цю платформу у мене більше досвіду розробки, ніж під Android, а по-друге, інтерфейс системи цілком простий для сприйняття людиною, яка взагалі не має ніякого досвіду в роботі з інтерфейсами.
Розробка велася, коли тільки-тільки вийшло оновлення GDR2 для Windows Phone 8.0, в якій додали підтримку радіо. Потрібно було ще знайти апарат з microSD-картою і яскравим немаленьким екраном. Якраз після тижня пошуків у Росії запустилася модель Nokia Lumia 625 , яка на той момент єдина мала GDR2, а також найбільший екран по діагоналі (4.7 ").
 
Отже, смартфон їде з Москви, колонка — з Америки, залишилося вибрати, яка док-станція буде добиратися до мене з Китаю.
Я забув згадати, що в усьому доводилося витримувати кольоровий стиль: колонка і смартфон купувалися виключно білого кольору, тому що я враховував інтер'єр, в якому ця конструкція збиралася стояти. Виявилося, що білих док-станцій, з роз'ємом microUSB дуже мало. Мабуть, тому, що в Китаї вважається, раз біле — значить для Apple, раз чорне — значить все інше. Ще захотілося мати другу виїмку на док-станції для того, щоб можна було ставити смартфон горизонтально для перегляду відео (хіба мало). Така док-станція взагалі була одна. Вирішено було замовити дві: з доп. виїмкою і без.
 
На жаль, Китай засмутив. Роз'єм в док-станції з доп. виїмкою розташовувався рівно під прямим кутом до поверхні, що було дуже незручно. Зате в док-станції без виїмки роз'єм розташовувався як треба — під невеликим кутом. Вирішено було просто склеїти док-станції разом — вийшла кумедна драбинка, яка, до речі, більш стійка при натисканні на смартфон, оскільки важче в два рази.
 
 Ð´Ð¾Ðº-станция
 
У будь-якого Windows Phone є одна непотрібна робити — кнопка пошуку. Якщо поставити регіон USA, а пошук за замовчуванням Bing, то так — запускається більш-менш путнє додаток, але нам в даному контексті ця кнопка взагалі не потрібна, тому просто заклеюємо її, щоб не натиснути ненароком. Ідею підглянув у співробітників Яндекса, навіть наклейка однойменна.
 
 ÐºÐ½Ð¾Ð¿ÐºÐ¸
 
 

Прикручуємо радіо

Тут розкрився черговий прорахунок. Оскільки радіо в смартфоні використовує навушники як антену, то при бездротовому підключенні до колонки радіо просто не включається. Пізніше вийшло змусити його працювати через код, але воно запрацювало виключно через вбудований динамік. Довелося підключати колонку до смартфону кабелем.
У Windows Phone 8.0 чомусь відразу не включили API для роботи з радіо, тому він працює тільки в оновленні GDR2 і вище (при наявності апаратної підтримки радіо, звичайно).
 
З радіо виявилося працювати досить просто:
 
 
FMRadio radioInstance = FMRadio.Instance;
// Выставляем регион 
radioInstance.CurrentRegion = RadioRegion.Europe;
// Включаем радио
radioInstance.PowerMode = RadioPowerMode.On;
// Выставляем частоту
radioInstance.Frequency = frequency;

Frequency — це і є частота радіостанції, яку нам треба міняти. У вбудованій програмі «Радіо» є режим пошуку радіостанції. На жаль, пошуки по успішної його реалізації ні до чого не привели.
Нічого страшного: заміряємо частоти, які приймаються в тому місці, де стоятиме смартфон і просто прописуємо хардкодом. Потім створюємо кнопки і на кожну навішуємо по радіостанції. Кнопки робимо великими, щоб можна було особливо не цілитися.
Додаємо кнопку "Назад" у самому верху, щоб не морочитися з апаратними кнопками: в Lumia 625 апаратні кнопки не підсвічуються, а на екрані кнопку не побачити буде складно.
 
 Ñ€Ð°Ð´Ð¸Ð¾
 
 

Вирішуємо проблему з виключенням екрану

Отже, радіо працює. Є побоювання, що навіть такий простий жест розблокування, як свайп вгору, бабусі буде скрутний. Значить треба мінімізувати його використання, відключивши блокування екрана.
У різних прошивках Windows Phone зустрічається різний набір режимів часу для відключення екрану. Nokia Lumia 920 (Не AT & T) — взагалі єдина Nokia на WP 8.0, яка має опцію «Відключати дисплей через: Ніколи» . В інших апаратах цей пункт випиляний і коштує максимум 5 хвилин.
 
Для порівняння: ліворуч Nokia 920, праворуч 1020 (теж саме на 520, 620, 625, 720, 820 і 920 AT & T).
 
 9201020
 
Але починаючи з GDR2 є ж навігаційні програми, які не вимикають дисплей — значить якось це можна зробити в коді. Ок, вовни MSDN і знаходимо:
 
 
PhoneApplicationService phoneAppService = PhoneApplicationService.Current;
phoneAppService.UserIdleDetectionMode = IdleDetectionMode.Disabled;

Ці рядки тримають дисплей включеним, якщо тільки користувач сам не натиснув кнопку блокування. Це те, що потрібно.
 
 

Дружимо додаток з картою пам'яті

Тепер нам потрібно реалізувати роботу з картою пам'яті. Хочеться, щоб на екрані з'являлися кнопки з назвами папок з музикою також, як в режимі радіо кнопки з радіостанціями.
Але є проблема: Windows Phone вміє працювати з музикою, але тільки якщо музика зашита в самому додатку (прощай карта пам'яті і швидка заміна контенту), або якщо музика обов'язково лежить в папці Music (прощай робота з папками).
Милиця знайшовся нешвидко.
Спочатку в маніфесті WMAppManifest.xml повідомляємо системі, що ми будемо розпізнавати тільки свій формат файлів на карті пам'яті, а інші файли ми помічати не будемо. Причому формат буде містити mp3-контент. Нехай формат буде називатися, наприклад, «mp3d» (можна назвати як завгодно, окрім загальновідомих розширень).
 
 
<Extensions>
      <FileTypeAssociation Name="mp3" NavUriFragment="fileToken=%s" TaskID="_default">
        <SupportedFileTypes>
          <FileType ContentType="application/mp3">.mp3d</FileType>
        </SupportedFileTypes>
      </FileTypeAssociation>
    </Extensions>

Мінус в тому, що нам доведеться перейменувати всі mp3-файли в mp3d-файли, але команда ren зробить все за нас.
 
 
ren *.mp3 *mp3d

Тепер, пишемо метод, який чіпляється до картки і формує список підпапок моєї папки з музикою.
 
 
private async Task<List<ExternalStorageFolder>> ReadFoldersFromSdAsync()
{
	List<ExternalStorageFolder> folders = new List<ExternalStorageFolder>();
    // Запрашиваем SD-карту
    ExternalStorageDevice _sdCard = (await ExternalStorage.GetExternalStorageDevicesAsync()).FirstOrDefault();

    // Если карта есть
    if (_sdCard != null)
    {
		// Запрашиваем папку MyMusic
        ExternalStorageFolder routesFolder = await _sdCard.GetFolderAsync("MyMusic");
        // Запрашиваем все подпапки в этой папке
        IEnumerable<ExternalStorageFolder> routeFolders = await routesFolder.GetFoldersAsync();
        folders = routeFolders.ToList();
    }
    return folders;
}

Використовуємо цей метод, створюючи кнопки і додаючи їх до списку (стилі опущу — вони є в исходниках). У Tag кладу поточну папку, щоб потім до неї достукатися по кліку (OnTap).
 
 
foreach (var f in folders)
{
	IEnumerable<ExternalStorageFile> files = await f.GetFilesAsync();
    if (files.Count() > 0)
    {
		Button button = new Button
        {
			Tag = f,
            Height = 85,
            Width = 456,
            Content = f.Name
        };
        button.Tap += this.OnTap;
        ContentStack.Children.Add(button);
    }
} 

Усередині OnTap-івенту шаманів: копіюємо mp3d-файл всередину програми у вигляді mp3-файлу myFile.mp3 , беремо URI скопійованого файлу і скармливаем MediaElement'у в якості ресурсу:
 
 
IEnumerable<ExternalStorageFile> files = await folder.GetFilesAsync();

// Перемешиваем файлы
...
// Берем первый файл с муз.композицией
ExternalStorageFile file = files.First();
Uri uri = null;
// Считываем из файла
using (Stream streamToRead = await file.OpenForReadAsync())
{
	if (streamToRead.Length <= int.MaxValue)
    {
		int length = (int)streamToRead.Length;
        Byte[] bytes = new Byte[length];
        streamToRead.Read(bytes, 0, length);

		// Запрашиваем локальное хранилище приложения и создаем файл
        StorageFolder local = Windows.Storage.ApplicationData.Current.LocalFolder;
        var fileToWrite = await local.CreateFileAsync("myFile.mp3", CreationCollisionOption.ReplaceExisting);
        // Записываем в локальный файл нашу композицию
        using (Stream streamToWrite = await fileToWrite.OpenStreamForWriteAsync())
        {
			streamToWrite.Write(bytes, 0, length);
        }
        // Формируем URI на локальный файл
        uri = new Uri(fileToWrite.Path, UriKind.Absolute);
    }
}
if (uri != null)
{
	MusicElement.Source = uri;
}

Музика грає, рухаємося далі.
 
 

Пишемо час на заставці

Було вирішено зробити так, щоб після закінчення якогось часу бездіяльності (не натисканням жодної кнопки) на екрані з'являлися крупно годинник, число і день тижня.
Для того, щоб з'являлося час, заводимо таймер з інтервалом в одну секунду:
 
 
DispatcherTimer dtm = new DispatcherTimer();
dtm.Interval = TimeSpan.FromSeconds(1);
dtm.Tick += OnTimerTick;
dtm.Start();

За івенту вважаємо кількість тиків і якщо воно дорівнює 29, то показуємо час на екрані:
 
 
private void OnTimerTick(Object s, EventArgs e)
{
    UpdateDate();
    _ticks++;
    if (_ticks == 29)
    {
		// Показываем время
	}
}

При натисканні на будь-яку іншу кнопку скидаємо _ticks в нуль.
Крім цього, таймер виконує функцію оновлення часу раз на секунду: ми викликаємо функцію, яка парсит DateTime.Now і розподіляє по текстових полях.
 
 

Додаємо слайд-шоу

Дивитися просто на час нудно, тому зробимо підкладку зі слайд-шоу з фотографій. Де можна дістати багато фотографій одного розміру і гарного з естетичної точки зору змісту? Із сайту Bing!
Фотографії одного розміру мені знадобилися через те, що їх дуже зручно підставляти в одну і ту ж анімацію: нічого не зіб'ється і не попливе не туди.
На торрентах лежать архіви, але там фотографії різних розмірів — не піде. Є відмінний сервіс , що дозволяє отримати картинки Bing, але картинки тільки під екран смартфона (я хочу більше), і тільки за останній тиждень.
Нарешті, знайшов архів , що задовольняє моїм вимогам. Залишилося тільки викачати.
Картинки були складені в папку Pictures на сам телефон.
Додатком було сказано брати ці картинки по одній у випадковому порядку:
 
 
bg.Source = PictureDecoder.DecodeJpeg(_mediaLibrary.Pictures[_random.Next(_imageQuantity)].GetImage());

Потім малюємо анімацію, в якій об'єкт Image переміщається горизонтально, а після змінює картинку на наступну.
 
 Ð·Ð°ÑÑ‚авка
 
 

Малюємо значки

Інтерфейс Windows Phone виявився дуже доречним, оскільки вийшло винести на робочий стіл величезні ярлики на додатки, за якими вже точно не схибиш. Оскільки ми робимо елементарний інтерфейс, то значками виступили просто слова «Радіо» і «Музика».
 
 Ð¸ÐºÐ¾Ð½ÐºÐ¸
 
На робочий стіл виніс також два ярлика на SPB TV : Перший канал і Культура.
 
 

Пишемо інструкцію

Як би я не старався зробити інтерфейс простим, я не міг передбачити, як з ним подружиться моя бабуся, тому написав інструкцію з скріншот і фотографіями. Інструкцію опублікую разом з вихідними кодами — раптом кому знадобиться для бабусі.
 
 

Підсумки

Найголовніше моє побоювання не справдилося: не минуло й двох хвилин, як я почав пояснювати бабусі, як користуватися додатком, а вона вже сама почала натискати на кнопки і ярлики, ставити пісні, закривати і відкривати програми. Блокування сприйняла на відмінно, сказала, що це ніби «шторку підняти або опустити». Так що цілі були успішно досягнуті — тепер у неї звучить улюблена музика. Подарунок своїми руками вдався!
 
 Ð³Ð¾Ñ‚ово
 
 Ісходникі та інструкція .

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.