/**
   * Send restRequest using RestClient's sendAsync method. Note: Synchronous calls are not allowed
   * from code running on the UI thread.
   *
   * @param restRequest
   */
  private void sendFromUIThread(RestRequest restRequest) {
    client.sendAsync(
        restRequest,
        new AsyncRequestCallback() {
          private long start = System.nanoTime();

          @Override
          public void onSuccess(RestRequest request, RestResponse result) {
            try {
              long duration = System.nanoTime() - start;
              println(result);
              int size = result.asString().length();
              int statusCode = result.getStatusCode();
              printRequestInfo(duration, size, statusCode);
              extractIdsFromResponse(result.asString());
            } catch (Exception e) {
              printException(e);
            }

            EventsObservable.get().notifyEvent(EventType.RenditionComplete);
          }

          @Override
          public void onError(Exception exception) {
            printException(exception);
            EventsObservable.get().notifyEvent(EventType.RenditionComplete);
          }
        });
  }
  /**
   * Sends a REST request.
   *
   * @param soql SOQL query.
   * @param obj Object being queried.
   */
  private void sendRequest(String soql, final String obj) throws UnsupportedEncodingException {
    final RestRequest restRequest =
        RestRequest.getRequestForQuery(getString(R.string.api_version), soql);
    client.sendAsync(
        restRequest,
        new AsyncRequestCallback() {

          @Override
          public void onSuccess(RestRequest request, RestResponse result) {
            try {
              final JSONArray records = result.asJSONObject().getJSONArray("records");
              if (obj.equals("Account")) {
                smartStoreIntf.insertAccounts(records);
              } else if (obj.equals("Opportunity")) {
                smartStoreIntf.insertOpportunities(records);
              } else {

                /*
                 * If the object is not an account or opportunity,
                 * we do nothing. This block can be used to save
                 * other types of records.
                 */
              }
            } catch (Exception e) {
              onError(e);
            } finally {
              progressDialog.dismiss();
              Toast.makeText(
                      MainActivity.this, "Records ready for offline access.", Toast.LENGTH_SHORT)
                  .show();
            }
          }

          @Override
          public void onError(Exception exception) {
            Toast.makeText(
                    MainActivity.this,
                    MainActivity.this.getString(
                        SalesforceSDKManagerWithSmartStore.getInstance()
                            .getSalesforceR()
                            .stringGenericError(),
                        exception.toString()),
                    Toast.LENGTH_LONG)
                .show();
          }
        });
  }
  private void getAccounts() {
    try {
      String accountId = getIntent().getStringExtra("ACCOUNT_ID");
      String soql = "select Id, Name from Contact where AccountId = '" + accountId + "'";
      RestRequest request = RestRequest.getRequestForQuery(apiVersion, soql);

      client.sendAsync(
          request,
          new AsyncRequestCallback() {

            public void onSuccess(RestResponse response) {
              try {
                if (response == null || response.asJSONObject() == null) return;

                JSONArray records = response.asJSONObject().getJSONArray("records");

                if (records.length() == 0) return;

                accounts = new String[records.length()];

                for (int i = 0; i < records.length(); i++) {
                  JSONObject album = (JSONObject) records.get(i);
                  accounts[i] = (i + 1) + ".  " + album.getString("Name");
                }
                ArrayAdapter<String> ad =
                    new ArrayAdapter<String>(
                        ContactListActivity.this, R.layout.list_item, accounts);
                lv.setAdapter(ad);
                EventsObservable.get().notifyEvent(EventType.RenditionComplete);
              } catch (Exception e) {
                e.printStackTrace();
                displayError(e.getMessage());
              }
            }

            public void onError(Exception exception) {
              displayError(exception.getMessage());
              EventsObservable.get().notifyEvent(EventType.RenditionComplete);
            }
          });

    } catch (Exception e) {
      e.printStackTrace();
      displayError(e.getMessage());
    }
  }