• 0
Alex Bozhko

TNotificationCenter. Можно ли изменить иконку?

Вопросы

Собствено, сабж. Можно ли изменить пиктограмму для нотификатора вообще и в Андроид в частности? По умолчанию,  показывается иконка приложения, а мне надо показывать несколько разных иконок.

 

Спасибо.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

26 ответов на этот вопрос

  • 0

Пока вижу только такой вариант: Нужно лезть в исходники и там менять, конкретно вот здесь "FMX.Notification.Android.pas", предположительно 132 и 137 строчки.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

У них там оч много заглушек ))

Советую поковырять android sdk. Я обычно так делаю ...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Коллеги, есть ли успехи в решении этого вопроса?

Поделитесь опытом плиз.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
В 02.09.2016 в 09:59, Pax Beach сказал:

Коллеги, есть ли успехи в решении этого вопроса?

Поделитесь опытом плиз.

Чтобы не лезть в исходники, можно сделать так для Android:

1. В Deployment : добавляешь нужную картинку X.png и устанавливаешь у картинки "Remote Path" "res\drawable\";

2. В коде перед созданием уведомления добавляешь:

const
    IMAGE = 'drawable/X'; //расширение картинки не указывается
var
    lId : Integer;
begin
    lId := TAndroidHelper.Context.getResources().getIdentifier(
        StringToJString(IMAGE),
        StringToJString('drawable'),
        TAndroidHelper.Context.getPackageName);
    TAndroidHelper.Context.getApplicationInfo.icon := lId; //именно отсюда потом берется Id картинки для локального уведомления

*Проверял на Android 4.4, в более поздних версиях могут быть различия, версия IDE =  Delphi 10 Seattle.

**В прошивках типа MIUI код выше может не работать из-за жестокого кеширования.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
2 часа назад, Fedor K сказал:

Чтобы не лезть в исходники, можно сделать так для Android:

1. В Deployment : добавляешь нужную картинку X.png и устанавливаешь у картинки "Remote Path" "res\drawable\";

2. В коде перед созданием уведомления добавляешь:

По поводу кэширования ресурсов, наверняка есть метод, который этим делом управляет, не разбирался пока.

В приведенном примере иконка изменится у всего приложения везде?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 1

Иконка изменится внутри приложения в рамах текущего контекста до ее завершения. С других приложений и в системе ничего не поменяется (см. прикрепление).

Чтобы не влиять на другой функционал, достаточно сделать следующее:

    //запоминаем ид по умолчанию
    lDefaultId := TAndroidHelper.Context.getApplicationInfo.icon;
    //устанавливаем нашу кастомную иконку
    TAndroidHelper.Context.getApplicationInfo.icon := lId;
    //создаем локальное уведомление
    NotificationCenter.PresentNotification(lNotification);
    //возвращаем обратно
    TAndroidHelper.Context.getApplicationInfo.icon := lDefaultId;

п.с. Если такой вариант не устраивает, всегда можно написать class helper for TBaseNotificationCenter и использовать классы JNotificationCompat_Builder, JNotificationManager, JNotification. Справка из developer.android.com.

Test.png

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Fedor K, Ваш вариант у меня не получается реализовать :(

У меня host-приложение со службой.

В приложении, в deployment, добавил 2 png файла, дал им имена в колонке remote name. Сделал deploy проекта.

В папке "\Android\Debug\имя_пакета\res\drawable" появились нужные файлы.

При создании службы выполняю
 

procedure TDMSrv.SetIDIconMed;
const
 img_is_med = 'drawable/med';
 img_not_med = 'drawable/nomed';
begin
//значок 1
  iIDIconMedY := TAndroidHelper.Context.getResources.getIdentifier(
                   StringToJString(img_is_med),
                   StringToJString('drawable'),
                   StringToJString('имя.пакета.host-приложения'));

// значок 2
  iIDIconMedN := TAndroidHelper.Context.getResources.getIdentifier(
                   StringToJString(img_not_med),
                   StringToJString('drawable'),
                   StringToJString('имя.пакета.host-приложения'));

end;

 

 

При оповещении:

procedure TDMSrv.LaunchNotification(const sTel, sTypeCall: string; idIconMed: integer);
begin
...
...
...
    //запоминаем значок приложения по умолчанию
    lDefaultId := TAndroidHelper.Context.getApplicationInfo.icon;

    //устанавливаем значок в зависимости от того, посредник или нет
    TAndroidHelper.Context.getApplicationInfo.icon := idIconMed;

    //показываем оповещение
    MyNotification.FireDate := IncSecond(Now, 1);
    NotificationCenter1.ScheduleNotification(MyNotification);

    //возвращаем значок приложения обратно
    TAndroidHelper.Context.getApplicationInfo.icon := lDefaultId;

    MyNotification.DisposeOf
end;

 

Вызываю, передавая нужный ID
 

LaunchNotification('...', '...', iIDIconMedY);

или

LaunchNotification('...', '...', iIDIconMedN);

 

Но всплывает при оповещении всё равно стандартный значок приложения.

 

Delphi Tokyo.

Screenshot_1.png

Изменено пользователем x11

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Проверил, что возвращает TAndroidHelper.Context.getResources.getIdentifier.

Первый значок - 0, второй - 2130837506.

Это неправильные значения?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
17 часов назад, x11 сказал:

img_is_med = 'drawable/med'; img_not_med = 'drawable/nomed';

Первый ресурс (ismed) - будет 0, т.е. его нет, потому как в деплое он обозначен как ismed.png. Второй ресурс нашелся.

На мой взгляд, лучше скопируйте себе System.Android.Notification, и внесите правки в него. Функция CreateNativeNotification (в Берлине 125 строка). Там можете и картинки назначать, и кнопку создать, и прогресс, и хронометр тот же вывести, в общем, процесс для творчества будет безграничен.

Так же и к предыдущей теме вашей пригодится - тот же .startForeground для сервиса, ну или "несмахиваемое" уведомление (.setOngoing(True))

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
19 минут назад, mazayhin сказал:

На мой взгляд, лучше скопируйте себе System.Android.Notification, и внесите правки в него.

Редактировать геном - это табу.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
20 минут назад, mazayhin сказал:

Первый ресурс (ismed) - будет 0, т.е. его нет,

 

Ошибка моя, нужно было ismed


img_is_med = 'drawable/ismed';

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
2 минуты назад, x11 сказал:

Редактировать геном - это табу.

ModernLV тоже не пользуетесь по религиозным соображениям?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Да, не пользуюсь. Я побоялся, что при выходе обновлений или новых версий Delphi, придётся всё снова править или ещё что-то.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Дак меняйте тогда только то, что не может поменяться по желанию идеры

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Ок.

Как вариант, что можно придумать, чтобы показать из службы что-то вроде Toast, но чтобы это небольшое окошко/надпись была на экране значительно дольше + вставить туда кроме надпись, ещё и значок.

Задача простая. При звонке показать, что номер телефона имеет такой-то признак. Чтобы пользователь смартфона видел это при вход./исход. звонке.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
В 10.09.2016 в 16:31, Fedor K сказал:

JNotificationCompat_Builder

Подскажите, а где в Delphi живёт JNotificationCompat_Builder?

Справка молчит.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Нашёл. В модуле AndroidApi.JNI.Support.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Может кому пригодится пример с использованием startForeground, а то в справке по Delphi не нашёл

uses System.Android.Notification, AndroidApi.JNI.Support; // для JNotification и JNotificationCompat_Builder
...
...
function TDMSrv.AndroidServiceStartCommand(const Sender: TObject; const Intent: JIntent; Flags, StartId: Integer): Integer;
Var
  Action: string;
  notification: JNotification;
  NotificationBuilder: JNotificationCompat_Builder;
begin
  Action := JStringToString(Intent.getAction);

//  if Action = 'StartService' then
//    CreateBroadcastReceiver;

  if Action = 'StopService' then
  begin
    JavaService.stopSelf;
    result := TJService.JavaClass.START_NOT_STICKY; // don't reload service
    Log('Service stoped');
    exit;
  end;

    NotificationBuilder := TJNotificationCompat_Builder.JavaClass.init(TAndroidHelper.Context);
    NotificationBuilder := NotificationBuilder.setSmallIcon(TAndroidHelper.Context.getApplicationInfo.icon);
    NotificationBuilder := NotificationBuilder.setContentTitle(StrToJCharSequence(TAndroidHelper.ApplicationTitle));
    NotificationBuilder := NotificationBuilder.setContentText(StrToJCharSequence('тело сообщения'));
    notification := NotificationBuilder.build;


  Self.JavaService.startForeground(1, notification);

  result := TJService.JavaClass.START_STICKY; // rerun service if host app stops
end;

Не нашёл информации, почему именно 1 здесь:

Self.JavaService.startForeground(1, notification);

 

Это в  DataModule, который в службе

TDMSrv = class(TAndroidService)

Изменено пользователем x11

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
2 часа назад, x11 сказал:

Может кому пригодится пример с использованием startForeground, а то в справке по Delphi не нашёл

При работе с API конкретной платформы советую использовать именно справку самой платформы. Находим реализацию на родном языке и пытаемся повторить тоже самое через wrappers от Delphi.

2 часа назад, x11 сказал:

Не нашёл информации, почему именно 1 здесь:

Self.JavaService.startForeground(1, notification);

1 - это идентификатор вашего сервиса отличный от 0 (см. подробнее Service | Android Developers), т.е. можете использовать любые положительные цифры. По сути и обычные уведомления тоже содержат такой идентификатор, но это практически редко используется.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
7 часов назад, Fedor K сказал:

Находим реализацию на родном языке и пытаемся повторить тоже самое через wrappers от Delphi.

к сожалению примеров, информации и справки очень мало, а сообщество FMX всё ещё не очень большое

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Не надо использовать START_STICKY если экшен в интенте был не пустой, т.к. при выгрузке службы и повторной попытке ее запуска системой (мы ж отметили что служба очень важная), придет пустой экшен.

Стартуйте с START_REDELIVER_INTENT, что бы система отправила тот же интент, с которым служба запускалась до выгрузки.

Цитата

к сожалению примеров, информации и справки очень мало, а сообщество FMX всё ещё не очень большое

Ну наверное в справке к FMX и не должно расписываться взаимодействие со всеми API целевых платформ. В качестве примера и для понимания принципов, как работать с ними, можно просто открыть исходники и сопоставить с доками того же гугла

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
58 минут назад, mazayhin сказал:

Не надо использовать START_STICKY

во всех примерах именно START_STICKY :(

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Разницы между START_STICKY  и START_REDELIVER_INTENT для меня нет.

Мне главное, чтобы при (пере)создании службы, был создан и BroadcastReceiver,который будет ждать вызова.
 

procedure TDMSrv.AndroidServiceCreate(Sender: TObject);
begin
  CreateBroadcastReceiver;
end;

procedure TDMSrv.CreateBroadcastReceiver;
begin
  if not assigned(fBroadcastReceiver) then
  begin
    fBroadcastReceiver := TCSBroadcastReceiver.Create(nil);
    Log('not assigned BroadcastReceiver, creating: ' + fBroadcastReceiver.ToString);
  end;

  fBroadcastReceiver.OnReceive := BroadcastReceiverOnReceive;
  fBroadcastReceiver.Clear;// Items.Clear;

  fBroadcastReceiver.RegisterReceiver;
  fBroadcastReceiver.Add(PHONE_STATE);
  fBroadcastReceiver.Add(NEW_OUTGOING_CALL);

  Log('CreateBroadcastReceiver');
end;

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти

  • Последние посетители   0 пользователей онлайн

    Ни одного зарегистрированного пользователя не просматривает данную страницу