Я провел последнюю неделю, работая над аналогичной проблемой, и могу предложить решение, подобное тому, которое использовал Том Таш (используя рефлексию), но, возможно, его будет немного легче понять. Следующий метод прочесывает уведомление для любого присутствующего текста и возвращает этот текст в ArrayList, если это возможно.
public static List<String> getText(Notification notification)
{
// We have to extract the information from the view
RemoteViews views = notification.bigContentView;
if (views == null) views = notification.contentView;
if (views == null) return null;
// Use reflection to examine the m_actions member of the given RemoteViews object.
// It's not pretty, but it works.
List<String> text = new ArrayList<String>();
try
{
Field field = views.getClass().getDeclaredField("mActions");
field.setAccessible(true);
@SuppressWarnings("unchecked")
ArrayList<Parcelable> actions = (ArrayList<Parcelable>) field.get(views);
// Find the setText() and setTime() reflection actions
for (Parcelable p : actions)
{
Parcel parcel = Parcel.obtain();
p.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
// The tag tells which type of action it is (2 is ReflectionAction, from the source)
int tag = parcel.readInt();
if (tag != 2) continue;
// View ID
parcel.readInt();
String methodName = parcel.readString();
if (methodName == null) continue;
// Save strings
else if (methodName.equals("setText"))
{
// Parameter type (10 = Character Sequence)
parcel.readInt();
// Store the actual string
String t = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel).toString().trim();
text.add(t);
}
// Save times. Comment this section out if the notification time isn't important
else if (methodName.equals("setTime"))
{
// Parameter type (5 = Long)
parcel.readInt();
String t = new SimpleDateFormat("h:mm a").format(new Date(parcel.readLong()));
text.add(t);
}
parcel.recycle();
}
}
// It's not usually good style to do this, but then again, neither is the use of reflection...
catch (Exception e)
{
Log.e("NotificationClassifier", e.toString());
}
return text;
}
Поскольку это, вероятно, немного похоже на черную магию, позвольте мне объяснить более подробно. Сначала мы извлекаем объект RemoteViews из самого уведомления. Это представляет представления в фактическом уведомлении. Чтобы получить доступ к этим представлениям, мы должны либо надуть объект RemoteViews (который будет работать только при наличии контекста активности), либо использовать отражение. Отражение будет работать в любом случае и является методом, используемым здесь.
Если вы изучите источник для RemoteViews здесь , вы увидите, что одним из закрытых членов является объект ArrayList of Action. Это представляет то, что будет сделано с представлениями после того, как они надуты. Например, после того, как представления созданы, setText () будет вызываться в некоторой точке каждого TextView, который является частью иерархии, чтобы назначить правильные строки. Что мы делаем, так это получаем доступ к этому списку действий и выполняем его. Действие определяется следующим образом:
private abstract static class Action implements Parcelable
{
...
}
Существует несколько конкретных подклассов Action, определенных в RemoteViews. Тот, который нас интересует, называется ReflectionAction и определяется следующим образом:
private class ReflectionAction extends Action
{
String methodName;
int type;
Object value;
}
Это действие используется для присвоения значений представлениям. Один экземпляр этого класса, вероятно, будет иметь значения {"setText", 10, "content of textview"}. Поэтому нас интересуют только элементы mActions, которые являются объектами «ReflectionAction» и каким-то образом назначают текст. Мы можем сказать конкретное «действие» как «ReflectionAction», изучив поле «TAG» в действии, которое всегда является первым значением, считываемым из посылки. Тэги 2 представляют объекты ReflectionAction.
После этого нам просто нужно прочитать значения из посылки в порядке, в котором они были написаны (см. Ссылку на источник, если вам интересно). Мы находим любую строку, которая установлена с помощью setText (), и сохраняем ее в списке. (setTime () также включен, если время уведомления также необходимо. Если нет, эти строки можно безопасно удалить.)
Хотя я обычно выступаю против использования отражения в подобных случаях, бывают случаи, когда это необходимо. Если нет доступного контекста действия, «стандартный» метод не будет работать должным образом, поэтому это единственный вариант.