Блог о Gentoo и около-линуксовым штукам

6 октября 2017 г.

Про сабвуфер в Dell Vostro 5470

14:26 Опубликовал Дмитрий Исаенко , Нет комментариев
Итак, проблема в том, что в linux он просто не работает. Исправить это - можно и нужно.

Для начала убедимся, что у нас в ядре включена опция CONFIG_SND_HDA_RECONFIG.

Symbol: SND_HDA_RECONFIG [=y]    
  Type  : boolean           
  Prompt: Allow dynamic codec reconfiguration       
   Location:   
     -> Device Drivers     
       -> Sound card support (SOUND [=y])          
         -> Advanced Linux Sound Architecture (SND [=m])       
  (1)       -> HD-Audio     
  Defined at sound/pci/hda/Kconfig:49 
  Depends on: SOUND [=y] && !M68K && !UML && SND [=m] && SND_HDA [=m]     
  Selected by: SND_HDA_PATCH_LOADER [=n] && SOUND [=y] && !M68K && !UML && SND [=m] && SND_HDA [=m]
Теперь поставим пакет alsa-tools:
# emerge alsa-tools 
Из него нам понадобиться hdajackretask. Запускаем его и выбираем Realtek ALC290. Далее жмём "Show unconnected pins" и находим 0x17.
Теперь выбираем "Override" и выставляем "Internal Speaker (LFE)"

В конце жмём "Install boot override" и "Apply now". Проверяем, перезагружаемся и проверяем. Тебер саб должен работать.

3 сентября 2017 г.

О особенностях работы WiFi 5Ghz (AC) на Archer C7 v.2

2:01 Опубликовал Дмитрий Исаенко Нет комментариев
Есть в TP-Link Archer C7 v.2 особые нюансы работы с WiFi. Точнее сказать, постоянные проблемы в OpenWRT. Мне понадобилось где-то пару лет, чтобы всё заработало как надо. Но обо всём по-порядку.

Проблема: соединение на 5Ghz постоянно обрывается.

Изучение dmesg не слишком помогло. В общем, чтобы этого не было, надо добавить в /etc/config/wireless, в категорию wlan0 (радио модуль AC) строку
option disassoc_low_ack '0'
Теперь соединение перестанет постоянно рваться.

Проблема: некоторые устройства после перезагрузки не видят сеть

Будто сеть не поднимается после перезагрузки, хотя в dmesg всё ок, в luci всё включено и работает. Если ещё раз перезагрузиться, то это иногда помогает и всё работает. Тут дело в том, что некоторые устройства (смартфоны там, планшеты) не видят каналов повыше. Ну вот на 36-48 работают нормально, а если сеть поднялась, например, на 136 то всё. Сети будто и нет.
Тут всё просто - в настройках меняем канал с 'auto' на '48' или какой другой свободный пониже. Сохраняем, применяем и всё снова работает.

Ниже пример типичного конфиг-файла.
# cat /etc/config/wireless 

config wifi-device 'radio0'
        option type 'mac80211'
        option hwmode '11a'
        option path 'pci0000:01/0000:01:00.0'
        option country 'US'
        option htmode 'VHT80'
        option channel '48'
        option txpower '23'

config wifi-iface
        option device 'radio0'
        option network 'lan'
        option mode 'ap'
        option ssid 'My AC'
        option encryption 'psk2'
        option key 'пароль'
        option disassoc_low_ack '0'

config wifi-device 'radio1'
        option type 'mac80211'
        option channel '11'
        option hwmode '11g'
        option path 'platform/qca955x_wmac'
        option country 'RU'
        option txpower '20'

config wifi-iface
        option device 'radio1'
        option network 'lan'
        option mode 'ap'
        option ssid 'My BGN'
        option encryption 'psk2'
        option key 'пароль'

config wifi-iface
        option device 'radio1'
        option mode 'ap'
        option ssid 'For PSP'
        option encryption 'psk'
        option macfilter 'allow'
        list maclist '00:1D:D9:A4:60:04'
        option key 'пароль'
        option network 'lan'
На этом всё.

1 сентября 2017 г.

Русификация Raspbian

2:02 Опубликовал Дмитрий Исаенко Нет комментариев
В Raspbian после установки нет русского языка и не отображаются кириллические символы в консольном шрифте. Несмотря на это, в системе есть все необходимые инструмены для устранения этой проблемы. Сегодня мы этим и займёмся, благо делается это достаточно просто.

Для начала зайдём в raspi-config и настроем нужную локаль:
# raspi-config
→ 4 Localisation Options Set up language and regional settings to match your location
→ I1 Change Locale        Set up language and regional settings to match your location
→ [*] ru_RU.UTF-8 UTF-8 
→ ru_RU.UTF-8
Теперь настроим шрифт консоли:
# dpkg-reconfigure console-setup
→ UTF-8
→ . комбинированный - латинский; славянская и не славянская кириллица 
→ TerminusBold
→ 8x16  
Если в списке нет Terminus, установим его:
# aptitude install console-terminus
Теперь настроим раскладку клавиатуры. Делать это нужно в двух файлах сразу, иначе вы столкнётесь с проблемой, что в GUI переключение раскладки не работает:
# nano /etc/default/keyboard
# KEYBOARD CONFIGURATION FILE 

# Consult the keyboard(5) manual page. 

XKBMODEL="pc105" 
XKBLAYOUT="us,ru" 
XKBVARIANT="," 
XKBOPTIONS="grp:alt_shift_toggle,compose:rwin,terminate:ctrl_alt_bksp,grp_led:scroll" 

BACKSPACE="guess"
# nano /home/pi/.config/lxkeymap.cfg 
[Global] 
layout = us, ru 
variant =  
option = grp:alt_shift_toggle,compose:rwin,terminate:ctrl_alt_bksp,grp_led:scroll 
Теперь установим индикатор раскладки на панель. Для этого добавим в конец файла следующие строки:
# nano /home/pi/.config/lxpanel/LXDE-pi/panels/panel

...

Plugin { 
 type=xkb 
 Config { 
   Model=pc105 
   LayoutList=us,ru 
   VariantsList=, 
   ToggleOpt=grp:alt_shift_toggle 
 } 
} 
На этом всё.

29 августа 2017 г.

OpenArena dedicated server @ Gentoo + Raspberry Pi

23:31 Опубликовал Дмитрий Исаенко , , Нет комментариев
Как делать сервер на коленке за 5 секунд.

Gentoo

Сначала ставим игрулю:
emerge games-fps/openarena 
Открываем порты на свой ПК:


Создаём конфиг:
$vim ~/.openarena/baseoa/oa1.cfg
sets sv_hostname "developer.su dedicated server"
sets sv_maxclients 10
//sv_master1 "dpmaster.deathmask.net"
seta sv_maxPing 150
seta sv_minPing 0
sv_pure 1
seta sv_maxRate 25000
sets sv_fps 25
sets sv_allowdownload 1

//sv_privateClients "2" // slots substracted from sv_maxclients
//sv_privatePassword " "

seta capturelimit 8
seta timelimit 15
seta fraglimit 35

seta bot_minplayers 3
//seta g_spskill 3.0

//set rconPassword "" // for remote ingame servercontrol

seta g_motd "Have fun"
seta g_quadfactor 3
seta g_inactivity 0
seta g_allowvote 1

//If you want to use unlagged functionality (since 0.7.6)
g_delagHitscan 1

//You might want to count pushing players over the side of a map as kills. In that case: 
seta g_awardPushing 1

//Special modes since 0.7.6:
//g_instantgib 1
//g_rockets 1
//g_vampire 0.25 //25%
//g_regen 5 //5 health per sec.

//Gametypes
// 0 = Free For All
// 1 = Tourney
// 3 = Team Deathmatch
// 4 = Capture The Flag
// 8 = Elimination
// 9 = CTF Elimination
// 10 = Last Man Standing
// 11 = Double Domination
// 12 = Domination
seta g_gametype 0

set d1 "map aggressor; set nextmap vstr d2"
set d2 "map oa_dm1; set nextmap vstr d3"
set d3 "map oa_dm2; set nextmap vstr d4"
set d4 "map oa_dm3; set nextmap vstr d5"
set d5 "map oa_dm4; set nextmap vstr d6"
set d6 "map kaos2; set nextmap vstr d7"
set d7 "map oa_dm5; set nextmap vstr d8"
set d8 "map oa_rpg3dm2;set nextmap vstr d9"
set d9 "map oa_shouse; set nextmap vstr d1"
wait
vstr d1 // start loop at d1

Запускаем всё это дело
$ openarena-ded +exec oa1.cfg
И потом жмём Enter. Без этого не сработает.

Raspberry Pi (Raspbian) 

Сначала ставим необходимые пакеты:
# aptitude install openarena-oacmp1 openarena-server
Важно установить не только сервер, но и карты (oacmp1). Все остальные зависимости подтянуться автоматически.

Далее копируем вышеприведенный конфиг сюда:
# vim /etc/openarena-server/server.cfg
Запускаем
# systemctl start openarena-server
Добавляем в автозагрузку:
# systemctl enable openarena-server

13 августа 2017 г.

Заметки о proftpd

7:23 Опубликовал Дмитрий Исаенко Нет комментариев
Что нужно для быстрой развёртки:
1. Удалить ACL. Если в системе не используется, то вообще никаких проблем.
# echo 'net-ftp/proftpd openssl -acl' >> /etc/portage/package.use
2. Поставить:
# emerge net-ftp/proftpd
3. Добавить пользователя для анонимусов:
# echo ftp:x:21:21:added by portage for ftpbase:/home/ftp:/sbin/nologin >> /etc/passwd
# echo 'ftp:x:21:' >> /etc/group
4. Добавить имя хоста в /etc/hosts
# hostname
myAwesomeHost
# vim /etc/hosts
127.0.0.1 localhost myAwesomeHost
5. Поправить (или не править, он и так хорош) конфиг
# vim /etc/proftpd/proftpd.conf

ServerName "ProFTPD Server on vostro"

ServerType standalone
DefaultServer on
RequireValidShell off
AuthPAM off
AuthPAMConfig ftp

Port 21

Umask 022

MaxInstances 30

User ftp
Group ftp

DefaultRoot ~

AllowOverwrite on
<limit site_chmod="">
  DenyAll
</limit><anonymous>
  User anonymous
  Group anonymous
  AnonRequirePassword   off
  RequireValidShell     off

  # Clients can login with the username "anonymous" and "ftp".
  UserAlias anonymous ftp

  # Limit the maximum number of parallel anonymous logins to 10.
  MaxClients 10

  # Prohibit the WRITE command for the anonymous users.
  <limit write="">
    DenyAll
  </limit>
</anonymous>
6. Добавить в автозагрузку и запустить
# rc-update add proftpd default
# /etc/etc/init.d/proftpd start

6 августа 2017 г.

ImageMagic: конвертирование иконок для проектов AndroidStudio

16:07 Опубликовал Дмитрий Исаенко Нет комментариев
Для разных dpi можно воспользоваться встроенным инструментом Image Asset или сгенерировать их с помощью ImageMagic. Для второго варианта понадобиться базовое изображение, созданное для разрешение extra-extra-extra-high-density (xxxdpi).
Дальше используем скрипт:
#!/bin/bash
######################################
# As input we use file xxxhdpi  file #
######################################
convert $1 -resize 75% $1_xxhdpi.png
convert $1 -resize 50% $1_xhdpi.png
convert $1_xhdpi.png -resize 75% $1_hdpi.png
convert $1 -resize 25% $1_mdpi.png
convert $1_mhdpi.png -resize 75% $1_ldpi.png

#    Examples:
#    36x36 (0.75x) for low-density
#    48x48 (1.0x baseline) for medium-density
#    72x72 (1.5x) for high-density
#    96x96 (2.0x) for extra-high-density
#    144x144 (3.0x) for extra-extra-high-density
#    192x192 (4.0x) for extra-extra-extra-high-density
Всё.

30 июля 2017 г.

Виджет для Android (без конфигуратора и с IntentService)

7:23 Опубликовал Дмитрий Исаенко , Нет комментариев
Сегодня мы будем создавать виджет, который может обновлять текст в нём по нажатию на одну из его четырёх кнопок. По нажатию на первые две будет вызываться MainActivity и обновлять текст на тот, что был передан в зависимости от того, какая из двух кнопок нажата. По нажатию на третью и четвёртую текст просто будет обновляться с помощью IntentSerive службы.
Код проекта доступен по ссылке https://github.com/developersu/MyWidgetNoConf/ .

Создадим новый проект с именем MyWidgetNoConf.

Опишем в манифесте все наши классы
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.blogspot.developersu.mywidgetnoconf">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <receiver android:name=".myWidget">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>

            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/widget_info" />
        </receiver>

        <service
            android:name=".MyIntentService"
            android:exported="false">
        </service>
    </application>

</manifest>
Теперь добавим XML с описанием возможнотей нашего виджета.

res→xml→widget_info.xml
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minHeight="180dp"
    android:minWidth="180dp"
    android:updatePeriodMillis="1800000"
    android:resizeMode="horizontal|vertical"
    />
Добавим layout-файл для виджета:
res→layout→my_widget_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical">
    <TextView
        android:id="@+id/widgetText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="0" />
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal">
        <Button
            android:id="@+id/widgetBtn"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Button 1" />
        <Button
            android:id="@+id/widgetBtn2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Button 2" />
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:orientation="horizontal">
        <Button
            android:id="@+id/widgetBtn3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button 3" />
        <Button
            android:id="@+id/widgetBtn4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Button 4" />
    </LinearLayout>
</LinearLayout>
Получится следующее:
Добавим классы MyIntentService и myWidget в основной package.
java→com.blogspot.developersu.mywidgetnoconf
→MyIntentService
→myWidget

Перейдём собственно к коду. Начнём с описания функционала виджета. Мы будем использовать onUpdate и onEnabled плюс функцию для определения функций клавиш. Сохранением данных тестовом поле пренебрежем.

Итак, для начала код:
package com.blogspot.developersu.mywidgetnoconf;

import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.widget.RemoteViews;

public class myWidget extends AppWidgetProvider {

    private void setWidgetIntents(Context context, AppWidgetManager appWidgetManager, int appWidgetIds[]){

        RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.my_widget_layout);

        for (int appWidgetId : appWidgetIds) {
            Intent intentBtn = new Intent(context, MainActivity.class);
            intentBtn.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
            intentBtn.putExtra("signature", "Button 1");
            intentBtn.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP );
            PendingIntent pi = PendingIntent.getActivity(context, appWidgetId+0, intentBtn, PendingIntent.FLAG_UPDATE_CURRENT); 
            rv.setOnClickPendingIntent(R.id.widgetBtn, pi);
            /*===================================================================*/
            // Set the same for button 2
            Intent intentBtn2 = new Intent(context, MainActivity.class);
            intentBtn2.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
            intentBtn2.putExtra("signature", "Button 2");
            intentBtn2.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP );
            PendingIntent pi2 = PendingIntent.getActivity(context, appWidgetId+1, intentBtn2, PendingIntent.FLAG_UPDATE_CURRENT);
            rv.setOnClickPendingIntent(R.id.widgetBtn2, pi2);
            /*===================================================================*/
            Intent intentBtn3 = new Intent(context, MyIntentService.class);
            intentBtn3.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
            intentBtn3.putExtra("signature", "Button 3");
            PendingIntent pi3 = PendingIntent.getService(context, appWidgetId+2, intentBtn3, PendingIntent.FLAG_UPDATE_CURRENT);
            rv.setOnClickPendingIntent(R.id.widgetBtn3, pi3);
            /*===================================================================*/
            Intent intentBtn4 = new Intent(context, MyIntentService.class);
            intentBtn4.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
            intentBtn4.putExtra("signature", "Button 4");
            PendingIntent pi4 = PendingIntent.getService(context, appWidgetId+3, intentBtn4, PendingIntent.FLAG_UPDATE_CURRENT);
            rv.setOnClickPendingIntent(R.id.widgetBtn4, pi4);
            appWidgetManager.updateAppWidget(appWidgetId, rv);
        }
    }
    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        super.onUpdate(context, appWidgetManager, appWidgetIds);
        setWidgetIntents(context, appWidgetManager, appWidgetIds);
    }

    @Override
    public void onEnabled(Context context) {
        AppWidgetManager awm = AppWidgetManager.getInstance(context);
        ComponentName compName = new ComponentName(context, myWidget.class);
        int[] widgetIds = awm.getAppWidgetIds(compName); // избыточно, но оставим для наглядности
        setWidgetIntents(context, awm, widgetIds);
    }
}
У нас есть функция setWidgetIntents которая принимает context, AppWidgetManager и множество ID среди которых есть и ID нашего виджета.
onUpdate — все данные у нас сразу имеются, так что просто передаём их в функцию
onEnabled — создаём объект  AppWidgetManager используя AppWidgetManager.getInstance(context), создаём ComponentName, который нам понадобится для вытаскивания передавая ему context и имя класса нашего виджета. IDs получаем через awm.getAppWidgetIds(compName).
setWidgetIntents — опеределим “RemoteViews rv” чтобы через него присваивать кнопкам действия. Далее создадим цикл для всех полученных widget ID.
Присваивать каждой кнопке действия следует используя PendingIntent. Для него требуется Intent в который в первом и втором случае обращён к MainActivitiy.class, а в третьем и четвёртом — к  MyIntentService.class.
В каждый такой Intent мы помещаем значение кнопки, которое будет передаваться. Это будет строка с именем “signature” и значением “Button N”, где N номер кнопки. Также передаём в него ID виджета, который инициировал вызов Intent.
Кроме того, в первых двух случаях мы определяем флаг  Intent.FLAG_ACTIVITY_SINGLE_TOP который говорит системе, что Activity не должен запускаться, если экземпляр уже существует в стеке. Таким образом, если activity уже запущен, то приниматься Intent с этим флагом будет в методе onNewIntent(). Альтернативой этому может быть установка в манифесте launchMode в singleTop (тогда этот флаг не нужен):
<activity android:name=".MainActivity" android:launchMode="singleTop">
Но этот вариант мы опустим. Трогать манифест не будем :)

Для обращения  к сервису этот флаг нам не потребуется, т.к. сервисы работают совсем не так как обычные Activity.
В конце мы “создаём” PendingIntent обращаясь к getActivity или getService. Оба этих метода принимают 4 значения: context, requestCode, Intent и флаги. В requestCode мы будем заносить ID нашего виджет плюс какую-то цифру, чтобы определить каждый PendingIntent отдельно. Их стандартное поведение может поначалу ввести в заблуждение, но, если коротко, то для разных PendingIntent лучше бы иметь разные коды. Используемый флаг PendingIntent.FLAG_UPDATE_CURRENT говорит системе, что если описываемый PendingIntent уже существует, то следует лишь заменить его extra-данные (те, что мы добавляли используя метод addExtra).

Далее присваеваем каждой кнопке действие и “применяем измененеия”
rv.setOnClickPendingIntent(R.id.widgetBtn, pi);
appWidgetManager.updateAppWidget(appWidgetId, rv);
Перейдём теперь к классу MyIntentService.
Класс наследует  IntentService и реагирует ловит входящие Intent в onHandleIntent. При запуске вызыватся конструктор, порождается новая нить, которая после выполнения метода  onHandleIntent() завершается.

Переходим к коду. Ничего, чтобы ещё хотелось выделить отдельно у меня нет.
package com.blogspot.developersu.mywidgetnoconf;

import android.app.IntentService;
import android.appwidget.AppWidgetManager;
import android.content.Intent;
import android.os.Bundle;
import android.widget.RemoteViews;


public class MyIntentService extends IntentService {

    public MyIntentService() {
        super("MyIntentService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        if (intent != null) {
            Bundle bndle = intent.getExtras();
            int wID = bndle.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
            String btnPressed = bndle.getString("signature");

            RemoteViews rv = new RemoteViews(getPackageName(), R.layout.my_widget_layout);
            AppWidgetManager awm = AppWidgetManager.getInstance(getApplicationContext());
            rv.setTextViewText(R.id.widgetText, btnPressed);
            awm.updateAppWidget(wID, rv);
        }
    }
}
Перейдём к MainActivity.

Тут как не было элементов управления так и нет. При получении Intent будет вызываться или onCreate() (если приложение закрыто) или onNewIntent() (если экземляр уже существует). Определением того, что мы получили в прилетевшем Intent будет заниматься метод handleIntent(), который принимает Intent.
В случае, если Intent не пустой и содержит хоть какие-то extras, будем пытаться(!) брать из него предполагаемые данные, т.е. строку “signature” и ID виджета.
Сразу после этого, выведем тост (Toast) с полученой информацией. Если пользователь просто запускает приложение, то ему покажется уведомление с widget ID = 0 и string = null. Далее приложение проверит эти поля и если они отличны от вышеприведённых значений, то присвоит строку в TextView виджета. За присвоение отвечает метод  sendBackToWidget().
package com.blogspot.developersu.mywidgetnoconf;

import android.appwidget.AppWidgetManager;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.RemoteViews;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    private void handleIntent(Intent i){
        String recievedString;
        Bundle bndle = i.getExtras();
        if (bndle != null) {
            int awID = bndle.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
            recievedString = bndle.getString("signature");
            Toast.makeText(getApplicationContext(), "Got intent from: " + Integer.toString(awID) + " " + recievedString, Toast.LENGTH_SHORT).show();
            if (awID != 0 && recievedString != null)
                sendBackToWidget(awID, recievedString);
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        handleIntent(getIntent());
        /* Почему мы вызываем handleIntent прямо тут? Потому, что если приложение закрыто а не работает в фоне, то при запуске его из виджета будет вызван
         * onCreate. Очевидно, что если это приложение уже будет находиться в стеке, то вызываться будет что-то другое :) */
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        //setIntent(intent);                    // Удобно использовать, если бы наш Intent был объявлен глобальной переменной. Тогда бы мы просто переопределили его через setintent().
        handleIntent(intent);
    }

    private void sendBackToWidget(int widgetID, String str){
        AppWidgetManager awManager = AppWidgetManager.getInstance(getApplicationContext());
        RemoteViews rv = new RemoteViews(getPackageName(), R.layout.my_widget_layout);
        rv.setTextViewText(R.id.widgetText, str);
        awManager.updateAppWidget(widgetID, rv);
    }
}
Код не идеален и оставляет множество мест для оптимизаций. Впрочем, нет ничего хуже, чем преждевременная оптимизация, так что оставлю это вам.

Посмотрим на то, что получилось.