2012-02-15 15 views
5

Necesito recuperar algo de texto de un objeto RemoteViews. Es posible que obtenga el LayoutId, pero no tengo idea de cómo recuperar el texto de un TextView que se encuentra en este RemoteView (a saber, una notificación).Recuperar texto de un objeto de RemoteViews

También el RemoteView solo contiene setters, pero no getters, así que supongo que tengo que usar el LayoutId (de alguna manera).

¿Me pueden ayudar con eso? ¡Gracias!

/edit: La razón por la que estoy preguntando esto es porque tengo un AccessibilityService que recupera la notificación. Por lo tanto, esta es la única forma de recuperar el valor.

/Edit2: Puedo utilizar este código para la recepción de la notificación:

@Override 
public void onAccessibilityEvent(AccessibilityEvent event) { 
    if (event.getEventType() == AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED) { 
     List<CharSequence> notificationList = event.getText(); 
     for (int i = 0; i < notificationList.size(); i++) { 
      Toast.makeText(this.getApplicationContext(), notificationList.get(i), 1).show(); 
     } 
     if (!(parcel instanceof Notification)) { 
      return; 
     } 
     final Notification notification = (Notification) parcel; 
     doMoreStuff(); 

    } 
} 

Con el objeto notification que tienen acceso a un RemoteViews (notification.contentView) ya una PendingIntent (notification.contentIntent). Para obtener el layoutId, puedo llamar contentView.getLayoutId()

+0

Probablemente sea mejor guardar la información en algún lugar ('SharedPreferences', etc.), y luego tener tanto' RemoteViews' como su otro código accedan a la información desde allí. –

+0

Bueno, estoy usando un 'AccesibilityService' para recuperar la notificación, así que no puedo simplemente almacenar el valor en alguna parte, porque mi aplicación no creó la notificación ;-) – Force

+0

¿Cómo se obtiene el ID de diseño? ¿Puedes publicar el código que recibe la notificación? –

Respuesta

4

Tomado de Extract notification text from parcelable, contentView or contentIntent:

Notification notification = (Notification) event.getParcelableData(); 
RemoteViews views = notification.contentView; 
Class secretClass = views.getClass(); 

try { 
    Map<Integer, String> text = new HashMap<Integer, String>(); 

    Field outerFields[] = secretClass.getDeclaredFields(); 
    for (int i = 0; i < outerFields.length; i++) { 
     if (!outerFields[i].getName().equals("mActions")) continue; 

     outerFields[i].setAccessible(true); 

     ArrayList<Object> actions = (ArrayList<Object>) outerFields[i] 
     .get(views); 
     for (Object action : actions) { 
      Field innerFields[] = action.getClass().getDeclaredFields(); 

      Object value = null; 
      Integer type = null; 
      Integer viewId = null; 
      for (Field field : innerFields) { 
       field.setAccessible(true); 
       if (field.getName().equals("value")) { 
        value = field.get(action); 
       } else if (field.getName().equals("type")) { 
        type = field.getInt(action); 
       } else if (field.getName().equals("viewId")) { 
        viewId = field.getInt(action); 
       } 
      } 

      if (type == 9 || type == 10) { 
       text.put(viewId, value.toString()); 
      } 
     } 

     System.out.println("title is: " + text.get(16908310)); 
     System.out.println("info is: " + text.get(16909082)); 
     System.out.println("text is: " + text.get(16908358)); 
    } 
} catch (Exception e) { 
    e.printStackTrace(); 
} 
+0

notification.contentView its deprecated ¿Existe alguna solución alternativa para extraer datos del objeto AccessibilityEvent por favor ayúdenme? –

0

CommonsWare en this question dice:

... widgets de aplicaciones son de sólo escritura: puede enviar datos a ellos, pero no puede leerlos . En cambio, cuando actualice el widget de su aplicación con el nuevo texto , deberá guardar ese texto en algún lugar, quizás en un archivo .

Su respuesta parece ser lógica.

7

me propuso una solución similar here que también utiliza la reflexión para resolver el problema, pero de una manera más accesible. Esta es mi solución. En este contexto, las RemoteViews provienen de una notificación, por lo que las primeras tres líneas probablemente se pueden ignorar si ya tiene acceso al objeto RemoteViews. El enlace en la página proporciona una explicación mucho más detallada de lo que está sucediendo realmente. Espero que esto ayude a cualquier persona con un problema similar.

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; 
} 
0

Si usted está apuntando en Android 19+, puede utilizar el siguiente código para conseguir el título/texto de un objeto de notificación sin utilizar ningún API privadas.

Notification noty = ...; 
Bundle extras = noty.extras; 
if (extras != null) { 
    String title = extras.getString(Notification.EXTRA_TITLE); 
    String text = extras.getString(Notification.EXTRA_TEXT); 
} 
Cuestiones relacionadas