Содержание статьи
Виджет с настройкой при добавлении
Многие из нас видели экран с настройками, который появляется при добавлении виджета на экран устройства. Например, погодный виджет может спросить: «А для какого города показывать прогноз?» Таким образом можно очень гибко настроить несколько виджетов одного и того же приложения для отображения разной информации.
Чтобы сэкономить труд на рутинных операциях, Android Studio может за нас в пару кликов создать рабочую заготовку с настраиваемым виджетом. От нас требуется только проставить нужные галочки в очень информативном мастере. Запускается он так: New-Widget-AppWidget
.
![Простой мастер, все ясно без документации](https://xakep.ru/wp-content/uploads/2017/04/123455/widget-scr-1.png)
В результате его работы у нас в проекте появятся два новых класса, которые автоматически пропишутся в манифест:
<receiver android:name=".NewAppWidget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/new_app_widget_info"/>
</receiver>
<activity android:name=".NewAppWidgetConfigureActivity">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
</intent-filter>
</activity>
Первый класс отвечает за сам виджет, а второй представляет собой активность для его настройки, которая запускается как раз при его добавлении. Такую активность мы можем запускать в разные моменты, но будет не очень понятно, какой именно виджет сейчас настраивается. Так что момент самый удачный и лучше больше никаких мест для данной настройки не использовать. Этот пример создания виджета описан во всех уроках и доках. Код простой, и ты сам в нем разберешься. Меня же заинтересовала возможность выбора иконки приложения, реализованная через виджет. Такая функция реализована в приложении Wifi Analyzer.
![]() |
![]() |
Вот же виджет. Негусто, но все же выбор |
Полезные и бесполезные виджеты
Поначалу я хотел просто рисовать иконку приложения в виджете. Это обосновано тем, что для добавления иконки на рабочий стол нужно добавить новое разрешение в манифест.
<uses-permission
android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
А так как пользователи не любят много полномочий у приложения и вдобавок при изменении разрешений в манифесте отключается механизм автообновления, то я старался сделать иконки через механизм виджетов. И как я ни упражнялся в дизайне, получить иконку один в один как оригинальная не выходило. Виной всему было непонимание работы системы. Виджет не предназначен для дублирования функциональности иконки, он может быть максимально на нее похож, но рисуются они по-разному, и на каждой прошивке свой лаунчер, рисующий рабочий стол с ярлыками и виджетами, как вздумается его разработчику.
Посмотрев чужое творчество, я поначалу был слегка обескуражен: у данного приложения виджет не имеет экрана настройки и всего лишь дублирует функциональность иконки, просто запуская приложение. На первый взгляд он совершенно бесполезен... Но когда я связался с авторами этого приложения, мне сказали, что виджет показывает количество непрочитанных писем. Такая функция есть в iOS.
Правда, не совсем понятно, зачем крохотному виджету сделали возможность менять свой размер? Или почему не сделали настройку выбора почтового ящика при добавлении виджета, например?
![Что-то тут не так](https://xakep.ru/wp-content/uploads/2017/04/123455/widget-scr-6.jpg)
Делаем иконки, как farproc
Раз не получилось сделать новую иконку через обычный виджет, нужно посмотреть, как поступают другие разработчики. В этом могут помочь разные инструменты, я обычно пользуюсь онлайн-декомпилятором или decompileandroid.com. Заглянув в манифест приложения Wifi Analyzer, я не нашел обычных описаний виджетов, как из примера выше. Но виджет-то был! И он как-то запускал экран с выбором иконки!
Методом глубокого поиска и научного тыка было установлено, что тут используется недокументированная функция. А в манифесте только и нужно, что добавить новую activity с особым фильтром:
<activity
android:name="com.farproc.wifi.analyzer.CreateShortcutScreen"
android:excludeFromRecents="true"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
android:noHistory="true">
<intent-filter>
<action android:name="android.intent.action.CREATE_SHORTCUT"/>
</intent-filter>
</activity>
Нужный экран мы запустили, а дальше уже полная свобода творчества. Вот, к примеру, совсем понятный, «обградленный» код добавления иконки:
private Intent m1641a(int i) {
Intent intent = new Intent();
Parcelable intent2 = new Intent(this, MainScreen.class);
intent.putExtra("android.intent.extra.shortcut.ICON_RESOURCE", ShortcutIconResource.fromContext(this, f1149c[i]));
intent.putExtra("android.intent.extra.shortcut.INTENT", intent2);
intent.putExtra("android.intent.extra.shortcut.NAME", getString(R.string.app_name));
return intent;
}
Все настоящие имена методов изменены, но от констант никуда не денешься. Они и доносят нам суть происходящего.
Как включить мобильные данные с виджета?
У упомянутого выше автора есть приложение Data Enabler Widget. Функциональность его позволяет включать и выключать мобильный интернет прямо с рабочего стола посредством виджета без root-прав. Этим виджетом я пользовался на старом Samsung с версией Android 2.3, но на последних версиях он работать не хочет :).
В декомпилированном виде функция включения GPRS данных выглядит так:
private void b(Context context)
{
if (a != null)
{
break MISSING_BLOCK_LABEL_56;
}
a = (ConnectivityManager)context.getSystemService("connectivity");
try
{
b = android/net/ConnectivityManager.getMethod("setMobileDataEnabled", new Class[] {
Boolean.TYPE
});
}
// Misplaced declaration of an exception variable
catch (Context context) { }
c = android/net/ConnectivityManager.getMethod("getMobileDataEnabled", new Class[0]);
return;
context;
}
Можно найти ее расширенную версию на Stack Overflow. Там же автор пишет, что она будет работать на всех версиях Android, а с версии 5.0 — только если приложение системное. По моим наблюдениям, так можно включать интернет до версии 4.3.
В основе этого метода лежит рефлексия, через нее вызывают непубличный метод. С точки зрения безопасности это большая проблема, так как любое приложение может включать мобильные данные и выходить в интернет. Поэтому в последних версиях Android эту лазейку прикрыли.
Об использовании скрытых методов
Какими бы широкими ни были возможности платформы Android, рано или поздно мы упираемся в ее границы. Вызов скрытых методов при помощи рефлексии позволяет нам эти границы расширить и сделать чуть больше, чем описано в документации. Вот, например, способ соединения Bluetooth-устройств.
Чаще всего границы платформы продиктованы безопасностью. Нельзя же позволять приложению с котиками подключаться к интернету без ведома пользователя или создавать Bluetooth-сети из устройств? В этом случае в угоду удобству нельзя жертвовать безопасностью. Поэтому пусть, чтобы получить новую порцию котиков, пользователь вручную подключает интернет каждый раз. В серьезных проектах скрытые методы использовать не будут, и крупные разработчики их не рекомендуют. В этом я полностью разделяю их мнение: не факт, что то, что работает сейчас, будет работать завтра. А в мире Android-разработки и без этого хватает головной боли...
Онлайн-декомпиляторы
Не может не радовать, что с каждым днем у нас все больше инструментов для разбора приложений.
Вот список уже трех подобных сайтов: