public static boolean isServiceAvailable() {
   boolean isAvailable = MyContextHolder.get().isReady();
   if (!isAvailable) {
     boolean tryToInitialize = false;
     synchronized (serviceAvailableLock) {
       tryToInitialize = mServiceAvailable;
     }
     if (tryToInitialize && !MyContextHolder.get().initialized()) {
       MyContextHolder.initialize(null, TAG);
       isAvailable = MyContextHolder.get().isReady();
     }
   }
   if (isAvailable) {
     long availableInMillis = 0;
     synchronized (serviceAvailableLock) {
       availableInMillis = timeWhenTheServiceWillBeAvailable - System.currentTimeMillis();
       if (!mServiceAvailable && availableInMillis <= 0) {
         setServiceAvailable();
       }
       isAvailable = mServiceAvailable;
     }
     if (!isAvailable) {
       MyLog.v(
           TAG,
           "Service will be available in "
               + java.util.concurrent.TimeUnit.MILLISECONDS.toSeconds(availableInMillis)
               + " seconds");
     }
   } else {
     MyLog.v(TAG, "Service is unavailable: Context is not Ready");
   }
   return isAvailable;
 }
 protected void copyMessageText(MessageEditorData editorData) {
   MyLog.v(this, "text='" + editorData.body + "'");
   if (!TextUtils.isEmpty(editorData.body)) {
     // http://developer.android.com/guide/topics/text/copy-paste.html
     ClipboardManager clipboard =
         (ClipboardManager)
             MyContextHolder.get().context().getSystemService(Context.CLIPBOARD_SERVICE);
     ClipData clip = ClipData.newPlainText(I18n.trimTextAt(editorData.body, 40), editorData.body);
     clipboard.setPrimaryClip(clip);
     MyLog.v(this, "clip='" + clip.toString() + "'");
   }
 }
 public Activity waitForNextActivity(String methodExt, long timeOut) throws InterruptedException {
   Activity nextActivity = mInstrumentation.waitForMonitorWithTimeout(activityMonitor, timeOut);
   MyLog.v(methodExt, "After waitForMonitor: " + nextActivity);
   assertNotNull("Next activity is opened and captured", nextActivity);
   TestSuite.waitForListLoaded(mInstrumentation, nextActivity, 2);
   activityMonitor = null;
   return nextActivity;
 }
 public static DownloadType load(String strCode) {
   try {
     return load(Long.parseLong(strCode));
   } catch (NumberFormatException e) {
     MyLog.v(TAG, "Error converting '" + strCode + "'", e);
   }
   return UNKNOWN;
 }
 public boolean execute(MessageContextMenu menu, MyAccount ma) {
   MyLog.v(this, "execute started");
   if (mIsAsync) {
     executeAsync1(menu, ma);
   } else {
     executeOnUiThread(menu, MessageEditorData.newEmpty(ma).setMsgId(menu.getMsgId()));
   }
   return false;
 }
 public void findRepliesRecursively(ConversationOneMessage oMsg) {
   MyLog.v(this, "findReplies for id=" + oMsg.msgId);
   List<Long> replies = MyProvider.getReplyIds(oMsg.msgId);
   oMsg.nReplies = replies.size();
   for (long replyId : replies) {
     ConversationOneMessage oMsgReply = new ConversationOneMessage(replyId, oMsg.replyLevel + 1);
     findPreviousMessagesRecursively(oMsgReply);
   }
 }
Beispiel #7
0
 private void saveNewSettings(boolean useExternalStorageNew, StringBuilder messageToAppend) {
   try {
     SharedPreferencesUtil.putBoolean(
         MyPreferences.KEY_USE_EXTERNAL_STORAGE, useExternalStorageNew);
     MyPreferences.onPreferencesChanged();
   } catch (Exception e) {
     MyLog.v(this, "Save new settings", e);
     messageToAppend.append("Couldn't save new settings. " + e.getMessage());
   }
 }
 private boolean addMessageToList(ConversationOneMessage oMsg) {
   boolean added = false;
   if (oMsgs.contains(oMsg)) {
     MyLog.v(this, "Message id=" + oMsg.msgId + " is in the list already");
   } else {
     oMsgs.add(oMsg);
     added = true;
   }
   return added;
 }
 /** Returns true if message was added false in a case the message existed already */
 private boolean addMessageIdToFind(long msgId) {
   if (msgId == 0) {
     return false;
   } else if (idsOfTheMessagesToFind.contains(msgId)) {
     MyLog.v(this, "findMessages cycled on the id=" + msgId);
     return false;
   }
   idsOfTheMessagesToFind.add(msgId);
   return true;
 }
 /**
  * InstrumentationTestCase.getInstrumentation().invokeContextMenuAction doesn't work properly
  *
  * @return success
  *     <p>Note: This method cannot be invoked on the main thread. See
  *     https://github.com/google/google-authenticator-android/blob/master/tests/src/com/google/android/apps/authenticator/TestUtilities.java
  */
 private boolean invokeContextMenuAction(
     final String methodExt, final MyListActivity activity, int position, final int menuItemId)
     throws InterruptedException {
   final String method = "invokeContextMenuAction";
   MyLog.v(
       methodExt, method + " started on menuItemId=" + menuItemId + " at position=" + position);
   boolean success = false;
   int position1 = position;
   for (long attempt = 1; attempt < 4; attempt++) {
     longClickAtPosition(methodExt, position1);
     if (mActivity.getPositionOfContextMenu() == position) {
       success = true;
       break;
     }
     MyLog.i(
         methodExt,
         method
             + "; Context menu created for position "
             + mActivity.getPositionOfContextMenu()
             + " instead of "
             + position
             + "; was set to "
             + position1
             + "; attempt "
             + attempt);
     position1 = position + (position1 - mActivity.getPositionOfContextMenu());
   }
   if (success) {
     mInstrumentation.runOnMainSync(
         new Runnable() {
           @Override
           public void run() {
             MyLog.v(methodExt, method + "; before performContextMenuIdentifierAction");
             activity.getWindow().performContextMenuIdentifierAction(menuItemId, 0);
           }
         });
     TestSuite.waitForIdleSync(mInstrumentation);
   }
   MyLog.v(methodExt, method + " ended " + success);
   return success;
 }
 public void selectListPosition(final String methodExt, final int positionIn)
     throws InterruptedException {
   final String method = "selectListPosition";
   MyLog.v(methodExt, method + " started; position=" + positionIn);
   mInstrumentation.runOnMainSync(
       new Runnable() {
         @Override
         public void run() {
           int position = positionIn;
           ListAdapter la = getListView().getAdapter();
           if (la.getCount() <= position) {
             position = la.getCount() - 1;
           }
           MyLog.v(
               methodExt, method + " on setSelection " + position + " of " + (la.getCount() - 1));
           getListView().setSelectionFromTop(position, 0);
         }
       });
   TestSuite.waitForIdleSync(mInstrumentation);
   MyLog.v(methodExt, method + " ended");
 }
 /** @return success */
 public boolean invokeContextMenuAction4ListItemId(
     String methodExt, long listItemId, ContextMenuItem menuItem) throws InterruptedException {
   final String method = "invokeContextMenuAction4ListItemId";
   boolean success = false;
   long id2 = listItemId;
   String msg = "";
   for (long attempt = 1; attempt < 4; attempt++) {
     TestSuite.waitForIdleSync(mInstrumentation);
     int position = getPositionOfListItemId(listItemId);
     msg =
         "listItemId="
             + listItemId
             + "; menu Item="
             + menuItem
             + "; position="
             + position
             + "; attempt="
             + attempt;
     MyLog.v(this, msg);
     if (getListItemIdAtPosition(position) == listItemId) {
       selectListPosition(methodExt, position);
       if (invokeContextMenuAction(methodExt, mActivity, position, menuItem.getId())) {
         id2 = getListItemIdAtPosition(position);
         if (id2 == listItemId) {
           success = true;
           break;
         } else {
           MyLog.i(
               methodExt,
               method + "; Position changed, now pointing to listItemId=" + id2 + "; " + msg);
         }
       }
     }
     ;
   }
   MyLog.v(methodExt, method + " ended " + success + "; " + msg);
   TestSuite.waitForIdleSync(mInstrumentation);
   return success;
 }
 private static Drawable loadDefaultAvatar(boolean lightTheme) {
   Drawable avatar = null;
   MyLog.v(AvatarDrawable.class, "Loading default avatar");
   Context context = MyContextHolder.get().context();
   if (context != null) {
     avatar =
         context
             .getResources()
             .getDrawable(
                 lightTheme ? R.drawable.ic_action_user_light : R.drawable.ic_action_user);
   }
   return avatar;
 }
  public void clickView(final String methodExt, final View view) throws InterruptedException {
    assertTrue(view != null);

    Runnable clicker =
        new Runnable() {
          @Override
          public void run() {
            MyLog.v(methodExt, "Before click view");
            view.performClick();
          }
        };

    mInstrumentation.runOnMainSync(clicker);
    MyLog.v(methodExt, "After click view");
    TestSuite.waitForIdleSync(mInstrumentation);
  }
  private void notifyForOneType(TimelineType timelineType, int numMessages) {
    if (numMessages == 0 || !areNotificationsEnabled(timelineType)) {
      return;
    }

    MyLog.v(this, "n=" + numMessages + "; timelineType=" + timelineType);

    int messageTitleResId;
    String messageText = "";
    switch (timelineType) {
      case MENTIONS:
        messageTitleResId = R.string.notification_title_mentions;
        messageText =
            I18n.formatQuantityMessage(
                myContext.context(),
                R.string.notification_new_mention_format,
                numMessages,
                R.array.notification_mention_patterns,
                R.array.notification_mention_formats);
        break;

      case DIRECT:
        messageTitleResId = R.string.notification_title_messages;
        messageText =
            I18n.formatQuantityMessage(
                myContext.context(),
                R.string.notification_new_message_format,
                numMessages,
                R.array.notification_direct_message_patterns,
                R.array.notification_direct_message_formats);
        break;

      case HOME:
      default:
        messageTitleResId = R.string.notification_new_home_title;
        messageText =
            I18n.formatQuantityMessage(
                myContext.context(),
                R.string.notification_new_tweet_format,
                numMessages,
                R.array.notification_home_patterns,
                R.array.notification_home_formats);
        break;
    }

    notify(timelineType, messageTitleResId, messageText);
  }
 public boolean onContextItemSelected(MenuItem item) {
   MyAccount ma = getMyActor();
   if (ma.isValid()) {
     UserListContextMenuItem contextMenuItem = UserListContextMenuItem.fromId(item.getItemId());
     MyLog.v(
         this,
         "onContextItemSelected: "
             + contextMenuItem
             + "; actor="
             + ma.getAccountName()
             + "; user="
             + getViewItem().mbUser.getNamePreferablyWebFingerId());
     return contextMenuItem.execute(this, ma);
   } else {
     return false;
   }
 }
Beispiel #17
0
 @Override
 protected TaskResult doInBackground2(Void... params) {
   TaskResult result = new TaskResult();
   if (!checkAndSetDataBeingMoved()) {
     return result;
   }
   try {
     moveAll(result);
   } finally {
     synchronized (MOVE_LOCK) {
       mDataBeingMoved = false;
     }
   }
   result.messageBuilder.insert(0, " Move " + (result.success ? "succeeded" : "failed"));
   MyLog.v(this, result.getMessage());
   return result;
 }
 private void checkInReplyToNameOf(ConversationOneMessage oMsg) {
   if (!SharedPreferencesUtil.isEmpty(oMsg.inReplyToName)) {
     MyLog.v(
         this,
         "Message id="
             + oMsg.msgId
             + " has reply to name ("
             + oMsg.inReplyToName
             + ") but no reply to message id");
     // Don't try to retrieve this message again.
     // It looks like such messages really exist.
     ConversationOneMessage oMsg2 = new ConversationOneMessage(0, oMsg.replyLevel - 1);
     // This allows to place the message on the timeline correctly
     oMsg2.createdDate = oMsg.createdDate - 60000;
     oMsg2.author = oMsg.inReplyToName;
     oMsg2.body = "(" + context.getText(R.string.id_of_this_message_was_not_specified) + ")";
     addMessageToList(oMsg2);
   }
 }
 public void clickListAtPosition(final String methodExt, final int position)
     throws InterruptedException {
   final String method = "clickListAtPosition";
   mInstrumentation.runOnMainSync(
       new Runnable() {
         // See
         // http://stackoverflow.com/questions/8094268/android-listview-performitemclick
         @Override
         public void run() {
           long listItemId = mActivity.getListAdapter().getItemId(position);
           MyLog.v(methodExt, method + "; on performClick, listItemId=" + listItemId);
           getListView()
               .performItemClick(
                   getListView().getAdapter().getView(position, null, null), position, listItemId);
         }
       });
   MyLog.v(methodExt, method + " ended");
   TestSuite.waitForIdleSync(mInstrumentation);
 }
 private void findPreviousMessagesRecursively(ConversationOneMessage oMsg) {
   if (!addMessageIdToFind(oMsg.msgId)) {
     return;
   }
   findRepliesRecursively(oMsg);
   MyLog.v(this, "findPreviousMessages id=" + oMsg.msgId);
   loadMessageFromDatabase(oMsg);
   if (oMsg.isLoaded()) {
     if (addMessageToList(oMsg)) {
       if (oMsg.inReplyToMsgId != 0) {
         findPreviousMessagesRecursively(
             new ConversationOneMessage(oMsg.inReplyToMsgId, oMsg.replyLevel - 1));
       } else {
         checkInReplyToNameOf(oMsg);
       }
     }
   } else {
     retrieveFromInternet(oMsg.msgId);
   }
 }
Beispiel #21
0
  /**
   * Get a cursor to the database
   *
   * @see android.content.ContentProvider#query(android.net.Uri, java.lang.String[],
   *     java.lang.String, java.lang.String[], java.lang.String)
   */
  @Override
  public Cursor query(
      Uri uri,
      String[] projection,
      String selectionIn,
      String[] selectionArgsIn,
      String sortOrder) {
    SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
    boolean built = false;
    String selection = selectionIn;
    String[] selectionArgs = selectionArgsIn;
    String sql = "";

    ParsedUri uriParser = ParsedUri.fromUri(uri);
    switch (uriParser.matched()) {
      case TIMELINE:
        qb.setDistinct(true);
        qb.setTables(TimelineSql.tablesForTimeline(uri, projection));
        qb.setProjectionMap(ProjectionMap.MSG);
        break;

      case TIMELINE_ITEM:
        qb.setTables(TimelineSql.tablesForTimeline(uri, projection));
        qb.setProjectionMap(ProjectionMap.MSG);
        qb.appendWhere(
            ProjectionMap.MSG_TABLE_ALIAS + "." + BaseColumns._ID + "=" + uriParser.getMessageId());
        break;

      case TIMELINE_SEARCH:
        qb.setTables(TimelineSql.tablesForTimeline(uri, projection));
        qb.setProjectionMap(ProjectionMap.MSG);
        String searchQuery = uriParser.getSearchQuery();
        if (!TextUtils.isEmpty(searchQuery)) {
          if (!TextUtils.isEmpty(selection)) {
            selection = " AND (" + selection + ")";
          } else {
            selection = "";
          }
          // TODO: Search in MyDatabase.User.USERNAME also
          selection = "(" + User.AUTHOR_NAME + " LIKE ?  OR " + Msg.BODY + " LIKE ?)" + selection;

          selectionArgs = addBeforeArray(selectionArgs, "%" + searchQuery + "%");
          selectionArgs = addBeforeArray(selectionArgs, "%" + searchQuery + "%");
        }
        break;

      case MSG_COUNT:
        sql = "SELECT count(*) FROM " + Msg.TABLE_NAME + " AS " + ProjectionMap.MSG_TABLE_ALIAS;
        if (!TextUtils.isEmpty(selection)) {
          sql += " WHERE " + selection;
        }
        break;

      case MSG:
        qb.setTables(Msg.TABLE_NAME + " AS " + ProjectionMap.MSG_TABLE_ALIAS);
        qb.setProjectionMap(ProjectionMap.MSG);
        break;

      case USER:
      case USERLIST:
        qb.setTables(User.TABLE_NAME);
        qb.setProjectionMap(ProjectionMap.USER);
        break;

      case USER_ITEM:
        qb.setTables(User.TABLE_NAME);
        qb.setProjectionMap(ProjectionMap.USER);
        qb.appendWhere(BaseColumns._ID + "=" + uriParser.getUserId());
        break;

      default:
        throw new IllegalArgumentException(uriParser.toString());
    }

    // If no sort order is specified use the default
    String orderBy;
    if (TextUtils.isEmpty(sortOrder)) {
      switch (uriParser.matched()) {
        case TIMELINE:
        case TIMELINE_ITEM:
        case TIMELINE_SEARCH:
          orderBy = Msg.DEFAULT_SORT_ORDER;
          break;

        case MSG_COUNT:
          orderBy = "";
          break;

        case USER:
        case USERLIST:
        case USER_ITEM:
          orderBy = User.DEFAULT_SORT_ORDER;
          break;

        default:
          throw new IllegalArgumentException(uriParser.toString());
      }
    } else {
      orderBy = sortOrder;
    }

    Cursor c = null;
    if (MyContextHolder.get().isReady()) {
      // Get the database and run the query
      SQLiteDatabase db = MyContextHolder.get().getDatabase().getReadableDatabase();
      boolean logQuery = MyLog.isVerboseEnabled();
      try {
        if (sql.length() == 0) {
          sql = qb.buildQuery(projection, selection, null, null, orderBy, null);
          built = true;
        }
        // Here we substitute ?-s in selection with values from selectionArgs
        c = db.rawQuery(sql, selectionArgs);
        if (c == null) {
          MyLog.e(this, "Null cursor returned");
          logQuery = true;
        }
      } catch (Exception e) {
        logQuery = true;
        MyLog.e(this, "Database query failed", e);
      }

      if (logQuery) {
        String msg = "query, SQL=\"" + sql + "\"";
        if (selectionArgs != null && selectionArgs.length > 0) {
          msg += "; selectionArgs=" + Arrays.toString(selectionArgs);
        }
        MyLog.v(TAG, msg);
        if (built) {
          msg =
              "uri="
                  + uri
                  + "; projection="
                  + Arrays.toString(projection)
                  + "; selection="
                  + selection
                  + "; sortOrder="
                  + sortOrder
                  + "; qb.getTables="
                  + qb.getTables()
                  + "; orderBy="
                  + orderBy;
          MyLog.v(TAG, msg);
        }
      }
    }

    if (c != null) {
      c.setNotificationUri(getContext().getContentResolver(), uri);
    }
    return c;
  }
 private void retrieveFromInternet(long msgId) {
   MyLog.v(this, "Message id=" + msgId + " should be retrieved from the Internet");
   MyServiceManager.sendCommand(
       new CommandData(CommandEnum.GET_STATUS, ma.getAccountName(), msgId));
 }
Beispiel #23
0
    private void moveDownloads(boolean useExternalStorageNew, StringBuilder messageToAppend) {
      String method = "moveDownloads";
      boolean succeeded = false;
      boolean done = false;
      boolean didWeCopyAnything = false;
      File dirOld = null;
      File dirNew = null;
      try {

        if (!done) {
          dirOld = MyStorage.getDataFilesDir(MyStorage.DIRECTORY_DOWNLOADS);
          dirNew =
              MyStorage.getDataFilesDir(
                  MyStorage.DIRECTORY_DOWNLOADS, TriState.fromBoolean(useExternalStorageNew));
          if (dirOld == null || !dirOld.exists()) {
            messageToAppend.append(" No old avatars. ");
            done = true;
            succeeded = true;
          }
          if (dirNew == null) {
            messageToAppend.append(" No directory for new avatars?! ");
            done = true;
          }
        }
        if (!done) {
          if (MyLog.isVerboseEnabled()) {
            MyLog.v(this, method + " from: " + dirOld.getPath());
            MyLog.v(this, method + " to: " + dirNew.getPath());
          }
          String filename = "";
          try {
            for (File fileOld : dirOld.listFiles()) {
              if (fileOld.isFile()) {
                filename = fileOld.getName();
                File fileNew = new File(dirNew, filename);
                if (copyFile(fileOld, fileNew)) {
                  didWeCopyAnything = true;
                }
              }
            }
            succeeded = true;
          } catch (Exception e) {
            String logMsg = method + " couldn't copy'" + filename + "'";
            MyLog.v(this, logMsg, e);
            messageToAppend.insert(0, " " + logMsg + ": " + e.getMessage());
          }
          done = true;
        }
      } catch (Exception e) {
        MyLog.v(this, e);
        messageToAppend.append(method + " error: " + e.getMessage() + ". ");
        succeeded = false;
      } finally {
        // Delete unnecessary files
        try {
          if (succeeded) {
            if (didWeCopyAnything) {
              for (File fileOld : dirOld.listFiles()) {
                if (fileOld.isFile() && !fileOld.delete()) {
                  messageToAppend.append(method + " couldn't delete old file " + fileOld.getName());
                }
              }
            }
          } else {
            if (dirNew != null && dirNew.exists()) {
              for (File fileNew : dirNew.listFiles()) {
                if (fileNew.isFile() && !fileNew.delete()) {
                  messageToAppend.append(method + " couldn't delete new file " + fileNew.getName());
                }
              }
            }
          }
        } catch (Exception e) {
          String logMsg = method + " deleting unnecessary files";
          MyLog.v(this, logMsg, e);
          messageToAppend.append(logMsg + ": " + e.getMessage());
        }
      }
      MyLog.d(this, method + " " + (succeeded ? "succeeded" : "failed"));
    }
Beispiel #24
0
 private boolean moveDatabase(
     boolean useExternalStorageNew, StringBuilder messageToAppend, String databaseName) {
   final String method = "moveDatabase";
   boolean succeeded = false;
   boolean done = false;
   /** Did we actually copied database? */
   boolean copied = false;
   File dbFileOld = null;
   File dbFileNew = null;
   try {
     dbFileOld = MyContextHolder.get().context().getDatabasePath(databaseName);
     dbFileNew =
         MyStorage.getDatabasePath(databaseName, TriState.fromBoolean(useExternalStorageNew));
     if (dbFileOld == null) {
       messageToAppend.append(" No old database " + databaseName);
       done = true;
     }
     if (!done) {
       if (dbFileNew == null) {
         messageToAppend.append(" No new database " + databaseName);
         done = true;
       } else {
         if (!dbFileOld.exists()) {
           messageToAppend.append(" No old database " + databaseName);
           done = true;
           succeeded = true;
         } else if (dbFileNew.exists()) {
           messageToAppend.insert(0, " Database already exists " + databaseName);
           if (!dbFileNew.delete()) {
             messageToAppend.insert(0, " Couldn't delete already existed files. ");
             done = true;
           }
         }
       }
     }
     if (!done) {
       if (MyLog.isVerboseEnabled()) {
         MyLog.v(this, method + " from: " + dbFileOld.getPath());
         MyLog.v(this, method + " to: " + dbFileNew.getPath());
       }
       try {
         if (copyFile(dbFileOld, dbFileNew)) {
           copied = true;
           succeeded = true;
         }
       } catch (Exception e) {
         MyLog.v(this, "Copy database " + databaseName, e);
         messageToAppend.insert(
             0, " Couldn't copy database " + databaseName + ": " + e.getMessage() + ". ");
       }
     }
   } catch (Exception e) {
     MyLog.v(this, e);
     messageToAppend.append(method + " error: " + e.getMessage() + ". ");
     succeeded = false;
   } finally {
     // Delete unnecessary files
     try {
       if (succeeded) {
         if (copied && dbFileOld != null && dbFileOld.exists() && !dbFileOld.delete()) {
           messageToAppend.append(method + " couldn't delete old files. ");
         }
       } else {
         if (dbFileNew != null && dbFileNew.exists() && !dbFileNew.delete()) {
           messageToAppend.append(method + " couldn't delete new files. ");
         }
       }
     } catch (Exception e) {
       MyLog.v(this, method + " Delete old file", e);
       messageToAppend.append(method + " couldn't delete old files. " + e.getMessage() + ". ");
     }
   }
   MyLog.d(this, method + "; " + databaseName + " " + (succeeded ? "succeeded" : "failed"));
   return succeeded;
 }
  /** Formats message as a View suitable for a conversation list */
  private View oneMessageToView(ConversationOneMessage oMsg) {
    final String method = "oneMessageToView";
    if (MyLog.isLoggable(this, MyLog.VERBOSE)) {
      MyLog.v(
          this,
          method
              + ": msgId="
              + oMsg.msgId
              + (oMsg.avatarDrawable != null
                  ? ", avatar=" + oMsg.avatarDrawable.getFileName()
                  : ""));
    }
    LayoutInflater inflater = LayoutInflater.from(context);
    int layoutResource = R.layout.message_conversation;
    if (!Activity.class.isAssignableFrom(context.getClass())) {
      MyLog.w(this, "Context should be from an Activity");
    }
    View messageView = inflater.inflate(layoutResource, null);
    messageView.setOnCreateContextMenuListener(contextMenu);

    float displayDensity = context.getResources().getDisplayMetrics().density;
    // See
    // http://stackoverflow.com/questions/2238883/what-is-the-correct-way-to-specify-dimensions-in-dip-from-java-code
    int indent0 = (int) (10 * displayDensity);
    int indentPixels = indent0 * oMsg.indentLevel;

    LinearLayout messageIndented = (LinearLayout) messageView.findViewById(R.id.message_indented);
    if (oMsg.msgId == selectedMessageId && oMsgs.size() > 1) {
      messageIndented.setBackgroundDrawable(
          context.getResources().getDrawable(R.drawable.message_current_background));
    }

    int viewToTheLeftId = 0;
    if (oMsg.indentLevel > 0) {
      View divider = messageView.findViewById(R.id.divider);
      RelativeLayout.LayoutParams layoutParams =
          new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1);
      layoutParams.leftMargin = indentPixels - 4;
      divider.setLayoutParams(layoutParams);

      if (MyLog.isLoggable(this, MyLog.VERBOSE)) {
        MyLog.v(this, "density=" + displayDensity);
      }
      viewToTheLeftId = 2;
      ImageView indentView =
          new ConversationIndentImageView(context, messageIndented, indentPixels);
      indentView.setId(viewToTheLeftId);
      ((ViewGroup) messageIndented.getParent()).addView(indentView);
    }

    if (MyPreferences.showAvatars()) {
      ImageView avatarView = new ImageView(context);
      int size = Math.round(AvatarDrawable.AVATAR_SIZE_DIP * displayDensity);
      avatarView.setScaleType(ScaleType.FIT_CENTER);
      RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(size, size);
      layoutParams.topMargin = 3;
      if (oMsg.indentLevel > 0) {
        layoutParams.leftMargin = 1;
      }
      if (viewToTheLeftId == 0) {
        layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);
      } else {
        layoutParams.addRule(RelativeLayout.RIGHT_OF, viewToTheLeftId);
      }
      avatarView.setLayoutParams(layoutParams);
      avatarView.setImageDrawable(oMsg.avatarDrawable.getDrawable());
      indentPixels += size;
      ((ViewGroup) messageIndented.getParent()).addView(avatarView);
    }
    messageIndented.setPadding(indentPixels + 6, 2, 6, 2);

    TextView id = (TextView) messageView.findViewById(R.id.id);
    id.setText(Long.toString(oMsg.msgId));
    TextView linkedUserId = (TextView) messageView.findViewById(R.id.linked_user_id);
    linkedUserId.setText(Long.toString(oMsg.linkedUserId));

    TextView author = (TextView) messageView.findViewById(R.id.message_author);
    TextView body = (TextView) messageView.findViewById(R.id.message_body);
    TextView details = (TextView) messageView.findViewById(R.id.message_details);

    author.setText(oMsg.author);

    TextView number = (TextView) messageView.findViewById(R.id.message_number);
    number.setText(Integer.toString(oMsg.historyOrder));

    if (!TextUtils.isEmpty(oMsg.body)) {
      body.setLinksClickable(true);
      body.setMovementMethod(LinkMovementMethod.getInstance());
      body.setFocusable(true);
      body.setFocusableInTouchMode(true);
      Spanned spanned = Html.fromHtml(oMsg.body);
      body.setText(spanned);
      if (!MbMessage.hasUrlSpans(spanned)) {
        Linkify.addLinks(body, Linkify.ALL);
      }
    }

    // Everything else goes to messageDetails
    String messageDetails = RelativeTime.getDifference(context, oMsg.createdDate);
    if (!SharedPreferencesUtil.isEmpty(oMsg.via)) {
      messageDetails +=
          " "
              + String.format(
                  MyContextHolder.get().getLocale(),
                  context.getText(R.string.message_source_from).toString(),
                  oMsg.via);
    }
    if (oMsg.inReplyToMsgId != 0) {
      String inReplyToName = oMsg.inReplyToName;
      if (SharedPreferencesUtil.isEmpty(inReplyToName)) {
        inReplyToName = "...";
      }
      messageDetails +=
          " "
              + String.format(
                  MyContextHolder.get().getLocale(),
                  context.getText(R.string.message_source_in_reply_to).toString(),
                  oMsg.inReplyToName)
              + " ("
              + msgIdToHistoryOrder(oMsg.inReplyToMsgId)
              + ")";
    }
    if (!SharedPreferencesUtil.isEmpty(oMsg.rebloggersString)
        && !oMsg.rebloggersString.equals(oMsg.author)) {
      if (!SharedPreferencesUtil.isEmpty(oMsg.inReplyToName)) {
        messageDetails += ";";
      }
      messageDetails +=
          " "
              + String.format(
                  MyContextHolder.get().getLocale(),
                  context
                      .getText(ma.alternativeTermForResourceId(R.string.reblogged_by))
                      .toString(),
                  oMsg.rebloggersString);
    }
    if (!SharedPreferencesUtil.isEmpty(oMsg.recipientName)) {
      messageDetails +=
          " "
              + String.format(
                  MyContextHolder.get().getLocale(),
                  context.getText(R.string.message_source_to).toString(),
                  oMsg.recipientName);
    }
    if (MyLog.isLoggable(this, MyLog.VERBOSE)) {
      messageDetails = messageDetails + " (i" + oMsg.indentLevel + ",r" + oMsg.replyLevel + ")";
    }
    details.setText(messageDetails);
    ImageView favorited = (ImageView) messageView.findViewById(R.id.message_favorited);
    favorited.setImageResource(
        oMsg.favorited ? android.R.drawable.star_on : android.R.drawable.star_off);
    return messageView;
  }
 public MyServiceManager() {
   MyLog.v(this, "Created, instanceId=" + instanceId);
 }
 private void logV(String method, Object obj) {
   if (MyLog.isVerboseEnabled()) {
     String message = (obj != null) ? obj.toString() : "";
     MyLog.v(this, String.valueOf(instanceId) + " " + method + "; " + message);
   }
 }
 @Override
 protected void onSuccessfulLoad() {
   MyLog.v(
       this,
       "Loaded attachment msgId:" + data.msgId + "; url:'" + data.getUrl().toExternalForm() + "'");
 }