Android Open Source - force_analytics_example Push Service






From Project

Back to project page force_analytics_example.

License

The source code is released under:

Copyright (c) 2011, salesforce.com, inc. All rights reserved. ======================================== Redistribution and use of this software in source and binary forms, with or without modificatio...

If you think the Android project force_analytics_example listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright (c) 2014, salesforce.com, inc.
 * All rights reserved.//from w ww  .  j a v a  2  s  .  c  om
 * Redistribution and use of this software in source and binary forms, with or
 * without modification, are permitted provided that the following conditions
 * are met:
 * - Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 * - Neither the name of salesforce.com, inc. nor the names of its contributors
 * may be used to endorse or promote products derived from this software without
 * specific prior written permission of salesforce.com, inc.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
package com.salesforce.androidsdk.push;

import java.io.IOException;
import java.net.URI;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.http.HttpStatus;
import org.json.JSONObject;

import android.app.AlarmManager;
import android.app.IntentService;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.PowerManager;
import android.util.Log;

import com.salesforce.androidsdk.accounts.UserAccount;
import com.salesforce.androidsdk.accounts.UserAccountManager;
import com.salesforce.androidsdk.app.SalesforceSDKManager;
import com.salesforce.androidsdk.auth.HttpAccess;
import com.salesforce.androidsdk.rest.ApiVersionStrings;
import com.salesforce.androidsdk.rest.ClientManager;
import com.salesforce.androidsdk.rest.RestClient;
import com.salesforce.androidsdk.rest.RestRequest;
import com.salesforce.androidsdk.rest.RestResponse;
import com.salesforce.androidsdk.rest.ClientManager.AccMgrAuthTokenProvider;
import com.salesforce.androidsdk.rest.RestClient.ClientInfo;

/**
 * This class houses functionality related to push notifications.
 * It performs registration and unregistration of push notifications
 * against the Salesforce connected app endpoint. It also receives
 * push notifications sent by the org to the registered user/device.
 *
 * @author bhariharan
 * @author ktanna
 */
public class PushService extends IntentService {

  private static final String TAG = "PushService";

    // Intent actions.
  public static final String GCM_REGISTRATION_CALLBACK_INTENT = "com.google.android.c2dm.intent.REGISTRATION";
    public static final String GCM_RECEIVE_INTENT = "com.google.android.c2dm.intent.RECEIVE";
    public static final String SFDC_REGISTRATION_RETRY_INTENT = "com.salesforce.mobilesdk.c2dm.intent.RETRY";

    // Extras in the registration callback intents.
    private static final String EXTRA_UNREGISTERED = "unregistered";
    private static final String EXTRA_ERROR = "error";
    private static final String EXTRA_REGISTRATION_ID = "registration_id";

    // Error constant when service is not available.
    private static final String ERR_SERVICE_NOT_AVAILABLE = "SERVICE_NOT_AVAILABLE";

  // Retry time constants.
    private static final long MILLISECONDS_IN_SIX_DAYS = 518400000L;
    private static final long SFDC_REGISTRATION_RETRY = 30000;

    // Salesforce push notification constants.
    private static final String MOBILE_PUSH_SERVICE_DEVICE = "MobilePushServiceDevice";
    private static final String ANDROID_GCM = "androidGcm";
    private static final String SERVICE_TYPE = "ServiceType";
    private static final String CONNECTION_TOKEN = "ConnectionToken";
    private static final String FIELD_ID = "id";

    // Wake lock instance.
    private static PowerManager.WakeLock WAKE_LOCK;

    private Context context;

    /**
     * This method is called from the broadcast receiver, when a push notification
     * is received, or when we receive a callback from the GCM service. Processing
     * of the message occurs here, and the acquired wake lock is released post processing.
     *
     * @param intent Intent.
     */
    static void runIntentInService(Intent intent) {
        final Context context = SalesforceSDKManager.getInstance().getAppContext();
        if (WAKE_LOCK == null) {
            final PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
            WAKE_LOCK = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
        }
        WAKE_LOCK.acquire();
        intent.setClassName(context, PushService.class.getName());
        final ComponentName name = context.startService(intent);
        if (name == null) {
          Log.w(TAG, "Could not start GCM service.");
        }
    }

  /**
   * Default constructor.
   */
  public PushService() {
    super(TAG);
    context = SalesforceSDKManager.getInstance().getAppContext();
  }

  @Override
  protected void onHandleIntent(Intent intent) {
    final Context context = SalesforceSDKManager.getInstance().getAppContext();

    /*
     * Grabs the extras from the intent, and determines based on the
     * bundle whether to perform the operation for all accounts or
     * just the specified account that's passed in.
     */
    final Bundle bundle = intent.getBundleExtra(PushMessaging.ACCOUNT_BUNDLE_KEY);
    UserAccount account = null;
    boolean allAccounts = false;
    if (bundle != null) {
      final String allAccountsValue = bundle.getString(PushMessaging.ACCOUNT_BUNDLE_KEY);
      if (PushMessaging.ALL_ACCOUNTS_BUNDLE_VALUE.equals(allAccountsValue)) {
        allAccounts = true;
      } else {
        account = new UserAccount(bundle);
      }
    }
    final UserAccountManager userAccMgr = SalesforceSDKManager.getInstance().getUserAccountManager();
    final List<UserAccount> accounts = userAccMgr.getAuthenticatedUsers();
    try {
            if (intent.getAction().equals(GCM_REGISTRATION_CALLBACK_INTENT)) {
              if (allAccounts) {
                if (accounts != null) {
                    for (final UserAccount userAcc : accounts) {
                            handleRegistration(intent, userAcc);
                    }
                }
              } else if (account != null) {
                    handleRegistration(intent, account);
              } else {
                handleRegistration(intent, userAccMgr.getCurrentUser());
              }
            } else if (intent.getAction().equals(GCM_RECEIVE_INTENT)) {
                onMessage(intent);
            } else if (intent.getAction().equals(SFDC_REGISTRATION_RETRY_INTENT)) {
              if (allAccounts) {
                if (accounts != null) {
                    for (final UserAccount userAcc : accounts) {
                          final String regId = PushMessaging.getRegistrationId(context,
                              account);
                          if (regId != null) {
                                onRegistered(regId, userAcc);
                          }
                    }
                }
              } else {
                if (account == null) {
                  account = userAccMgr.getCurrentUser();
                }
                  final String regId = PushMessaging.getRegistrationId(context,
                      account);
                  if (regId != null) {
                        onRegistered(regId, account);
                  }
              }
            }
        } finally {

          // Releases the wake lock, since processing is complete.
            if (WAKE_LOCK != null && WAKE_LOCK.isHeld()) {
                WAKE_LOCK.release();
            }
        }
  }

  /**
   * Handles a push notification message.
   *
   * @param intent Intent.
   */
  protected void onMessage(Intent intent) {
    if (intent != null) {
      final Bundle pushMessage = intent.getExtras();
      final PushNotificationInterface pnInterface = SalesforceSDKManager.getInstance().getPushNotificationReceiver();
      if (pnInterface != null && pushMessage != null) {
        pnInterface.onPushMessageReceived(pushMessage);
      }
    }
  }

    /**
     * Handles errors associated with registration or un-registration.
     *
     * @param error Error received from the GCM service.
     * @param account User account.
     */
    private void onError(String error, UserAccount account) {
        if (PushMessaging.isRegistered(context, account)) {
            handleUnRegistrationError(error, account);
        } else {
            handleRegistrationError(error, account);
        }
    }

    /**
     * Handles registration errors. Retries on service unavailable, and
     * bails out on other types of errors.
     *
     * @param error Error received from the GCM service.
     * @param account User account.
     */
    private void handleRegistrationError(String error, UserAccount account) {
      if (error != null && ERR_SERVICE_NOT_AVAILABLE.equals(error)) {
        scheduleGCMRetry(true, account);
      }
    }

    /**
     * Handles unregistration errors.
     *
     * @param error Error received from the GCM service.
     * @param account User account.
     */
    private void handleUnRegistrationError(String error, UserAccount account) {
      if (PushMessaging.isRegisteredWithSFDC(context, account)) {
        final String id = PushMessaging.getDeviceId(context, account);
        if (id != null) {
          unregisterSFDCPushNotification(id, account);
        }
      }
        context.sendBroadcast(new Intent(PushMessaging.UNREGISTERED_ATTEMPT_COMPLETE_EVENT));
        scheduleGCMRetry(false, account);
    }

    /**
     * Schedules retry of GCM registration or un-registration.
     *
     * @param register True - for registration retry, False - for un-registration retry.
     * @param account User account.
     */
    private void scheduleGCMRetry(boolean register, UserAccount account) {
        long backoffTimeMs = PushMessaging.getBackoff(context, account);
        final Calendar cal = Calendar.getInstance();
        cal.add(Calendar.MILLISECOND, (int) backoffTimeMs);
        final Intent retryIntent = new Intent(context, register ? RetryRegistrationAlarmReceiver.class
                : UnregisterRetryAlarmReceiver.class);
        retryIntent.putExtra(PushMessaging.ACCOUNT_BUNDLE_KEY, account.toBundle());
        final PendingIntent retryPIntent = PendingIntent.getBroadcast(context,
            1, retryIntent, PendingIntent.FLAG_ONE_SHOT);
        final AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), retryPIntent);

        // Next retry should wait longer.
        backoffTimeMs *= 2;
        PushMessaging.setBackoff(context, backoffTimeMs, account);
    }

    /**
     * Schedules retry of SFDC registration.
     *
     * @param when When to retry.
     * @param account User account.
     */
    private void scheduleSFDCRegistrationRetry(long when, UserAccount account) {
        final Calendar cal = Calendar.getInstance();
        cal.add(Calendar.MILLISECOND, (int) when);
        final Intent retryIntent = new Intent(context, SFDCRegistrationRetryAlarmReceiver.class);
        retryIntent.putExtra(PushMessaging.ACCOUNT_BUNDLE_KEY, account.toBundle());
        final PendingIntent retryPIntent = PendingIntent.getBroadcast(context,
            1, retryIntent, PendingIntent.FLAG_ONE_SHOT);
        final AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), retryPIntent);
    }

    /**
     * This method is called when registration with GCM is successful.
     *
     * @param registrationId Registration ID received from GCM service.
     * @param account User account.
     */
    private void onRegistered(String registrationId, UserAccount account) {
      long retryInterval = SFDC_REGISTRATION_RETRY;
      try {
          final String id = registerSFDCPushNotification(registrationId, account);
          if (id != null) {
            retryInterval = MILLISECONDS_IN_SIX_DAYS;
            PushMessaging.setRegistrationInfo(context, registrationId, id,
                account);
          } else {
              PushMessaging.setRegistrationId(context, registrationId, account);
          }
      } catch (Exception e) {
        Log.e(TAG, "Error occurred during SFDC registration.", e);
      } finally {
            scheduleSFDCRegistrationRetry(retryInterval, account);
      }
    }

    /**
     * This method is called when the device has been un-registered.
     *
     * @param account User account.
     */
    private void onUnregistered(UserAccount account) {
      try {
          final String id = PushMessaging.getDeviceId(context, account);
          unregisterSFDCPushNotification(id, account);
      } catch (Exception e) {
        Log.e(TAG, "Error occurred during SFDC un-registration.", e);
      } finally {
          PushMessaging.clearRegistrationInfo(context, account);
            context.sendBroadcast(new Intent(PushMessaging.UNREGISTERED_ATTEMPT_COMPLETE_EVENT));
            context.sendBroadcast(new Intent(PushMessaging.UNREGISTERED_EVENT));
        }
    }

    /**
     * Hits the Salesforce endpoint to register for push notifications.
     *
     * @param registrationId Registration ID.
     * @param account User account.
     * @return Salesforce ID that uniquely identifies the registered device.
     */
    private String registerSFDCPushNotification(String registrationId,
        UserAccount account) {
      final Map<String, Object> fields = new HashMap<String, Object>();
      fields.put(CONNECTION_TOKEN, registrationId);
      fields.put(SERVICE_TYPE, ANDROID_GCM);
      try {
        final RestClient client = getRestClient(account);
          final RestRequest req = RestRequest.getRequestForCreate(ApiVersionStrings.VERSION_NUMBER,
              MOBILE_PUSH_SERVICE_DEVICE, fields);
          if (client != null) {
              final RestResponse res = client.sendSync(req);
              String id = null;
              if (res.getStatusCode() == HttpStatus.SC_CREATED) {
                final JSONObject obj = res.asJSONObject();
                if (obj != null) {
                  id = obj.getString(FIELD_ID);
                }
              }
              return id;
          }
      } catch (Exception e) {
        Log.e(TAG, "Push notification registration failed.", e);
      }
      return null;
    }

    /**
     * Hits the Salesforce endpoint to un-register from push notifications.
     *
     * @param registeredId Salesforce ID that uniquely identifies the registered device.
     * @param account User account.
     * @return True - if un-registration was successful, False - otherwise.
     */
    private boolean unregisterSFDCPushNotification(String registeredId,
        UserAccount account) {
      final RestRequest req = RestRequest.getRequestForDelete(ApiVersionStrings.VERSION_NUMBER,
          MOBILE_PUSH_SERVICE_DEVICE, registeredId);
      try {
        final RestClient client = getRestClient(account);
        if (client != null) {
              final RestResponse res = client.sendSync(req);
              if (res.getStatusCode() == HttpStatus.SC_NO_CONTENT) {
                return true;
              }
        }
      } catch (IOException e) {
        Log.e(TAG, "Push notification un-registration failed.", e);
      }
      return false;
    }

    /**
     * Gets an instance of RestClient.
     *
     * @param account User account.
     * @return Instance of RestClient.
     */
    private RestClient getRestClient(UserAccount account) {
      final ClientManager cm = new ClientManager(SalesforceSDKManager.getInstance().getAppContext(),
          SalesforceSDKManager.getInstance().getAccountType(),
          SalesforceSDKManager.getInstance().getLoginOptions(), true);
      RestClient client = null;

      /*
       * The reason we can't directly call 'peekRestClient()' here is because
       * ClientManager does not hand out a rest client when a logout is in
       * progress. Hence, we build a rest client here manually, with the
       * available data in the 'account' object.
       */
      if (cm != null) {
        try {
              final AccMgrAuthTokenProvider authTokenProvider = new AccMgrAuthTokenProvider(cm,
                  account.getAuthToken(), account.getRefreshToken());
          final ClientInfo clientInfo = new ClientInfo(account.getClientId(),
              new URI(account.getInstanceServer()), new URI(account.getLoginServer()),
              new URI(account.getIdUrl()), account.getAccountName(), account.getUsername(),
                  account.getUserId(), account.getOrgId(),
                  account.getCommunityId(), account.getCommunityUrl());
                client = new RestClient(clientInfo, account.getAuthToken(),
                    HttpAccess.DEFAULT, authTokenProvider);
        } catch (Exception e) {
          Log.e(TAG, "Failed to get rest client.");
        }
      }
      return client;
    }

    /**
     * Handles registration callback.
     *
     * @param intent Intent.
     * @param account User account.
     */
    private void handleRegistration(Intent intent, UserAccount account) {
        final String registrationId = intent.getStringExtra(EXTRA_REGISTRATION_ID);
        final String error = intent.getStringExtra(EXTRA_ERROR);
        final String removed = intent.getStringExtra(EXTRA_UNREGISTERED);
        if (removed != null) {
            onUnregistered(account);
        } else if (error != null) {
            onError(error, account);
        } else {
            onRegistered(registrationId, account);
        }
    }

    /**
     * Broadcast receiver to retry the entire push registration process (GCM + SFDC).
     *
     * @author ktanna
     */
    public static class RetryRegistrationAlarmReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
          if (intent != null) {
            final Bundle accBundle = intent.getBundleExtra(PushMessaging.ACCOUNT_BUNDLE_KEY);
            if (accBundle != null) {
                    PushMessaging.register(context, new UserAccount(accBundle));
            }
          }
        }
    }

    /**
     * Broadcast receiver to retry SFDC push registration.
     *
     * @author ktanna
     */
    public static class SFDCRegistrationRetryAlarmReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
          if (intent != null) {
            final Bundle accBundle = intent.getBundleExtra(PushMessaging.ACCOUNT_BUNDLE_KEY);
            if (accBundle != null) {
                    PushMessaging.registerSFDCPush(context, new UserAccount(accBundle));
            }
          }
        }
    }

    /**
     * Broadcast receiver to retry GCM registration.
     *
     * @author ktanna
     */
    public static class UnregisterRetryAlarmReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
          if (intent != null) {
            final Bundle accBundle = intent.getBundleExtra(PushMessaging.ACCOUNT_BUNDLE_KEY);
            if (accBundle != null) {
                    PushMessaging.unregister(context, new UserAccount(accBundle));
            }
          }
        }
    }
}




Java Source Code List

com.salesforce.androidsdk.accounts.UserAccountManagerWithSmartStore.java
com.salesforce.androidsdk.accounts.UserAccountManager.java
com.salesforce.androidsdk.accounts.UserAccount.java
com.salesforce.androidsdk.app.SalesforceSDKManager.java
com.salesforce.androidsdk.app.UUIDManager.java
com.salesforce.androidsdk.app.UpgradeManager.java
com.salesforce.androidsdk.auth.AccountWatcher.java
com.salesforce.androidsdk.auth.AuthenticatorService.java
com.salesforce.androidsdk.auth.HttpAccess.java
com.salesforce.androidsdk.auth.LoginServerManager.java
com.salesforce.androidsdk.auth.OAuth2.java
com.salesforce.androidsdk.phonegap.ForcePlugin.java
com.salesforce.androidsdk.phonegap.JavaScriptPluginVersion.java
com.salesforce.androidsdk.phonegap.SDKInfoPlugin.java
com.salesforce.androidsdk.phonegap.SFAccountManagerPlugin.java
com.salesforce.androidsdk.phonegap.SalesforceOAuthPlugin.java
com.salesforce.androidsdk.phonegap.TestRunnerPlugin.java
com.salesforce.androidsdk.push.PushBroadcastReceiver.java
com.salesforce.androidsdk.push.PushMessaging.java
com.salesforce.androidsdk.push.PushNotificationInterface.java
com.salesforce.androidsdk.push.PushService.java
com.salesforce.androidsdk.rest.AdminPrefsManager.java
com.salesforce.androidsdk.rest.ApiVersionStrings.java
com.salesforce.androidsdk.rest.BootConfig.java
com.salesforce.androidsdk.rest.ClientManager.java
com.salesforce.androidsdk.rest.RestClient.java
com.salesforce.androidsdk.rest.RestRequest.java
com.salesforce.androidsdk.rest.RestResponse.java
com.salesforce.androidsdk.rest.files.ApiRequests.java
com.salesforce.androidsdk.rest.files.ConnectUriBuilder.java
com.salesforce.androidsdk.rest.files.FileRequests.java
com.salesforce.androidsdk.rest.files.RenditionType.java
com.salesforce.androidsdk.security.Encryptor.java
com.salesforce.androidsdk.security.PRNGFixes.java
com.salesforce.androidsdk.security.PasscodeManager.java
com.salesforce.androidsdk.smartstore.app.SalesforceSDKManagerWithSmartStore.java
com.salesforce.androidsdk.smartstore.app.UpgradeManagerWithSmartStore.java
com.salesforce.androidsdk.smartstore.phonegap.SmartStorePlugin.java
com.salesforce.androidsdk.smartstore.phonegap.StoreCursor.java
com.salesforce.androidsdk.smartstore.store.DBHelper.java
com.salesforce.androidsdk.smartstore.store.DBOpenHelper.java
com.salesforce.androidsdk.smartstore.store.IndexSpec.java
com.salesforce.androidsdk.smartstore.store.QuerySpec.java
com.salesforce.androidsdk.smartstore.store.SmartSqlHelper.java
com.salesforce.androidsdk.smartstore.store.SmartStore.java
com.salesforce.androidsdk.ui.AccountSwitcherActivity.java
com.salesforce.androidsdk.ui.CustomServerUrlEditor.java
com.salesforce.androidsdk.ui.LoginActivity.java
com.salesforce.androidsdk.ui.ManageSpaceActivity.java
com.salesforce.androidsdk.ui.OAuthWebviewHelper.java
com.salesforce.androidsdk.ui.PasscodeActivity.java
com.salesforce.androidsdk.ui.SalesforceAccountRadioButton.java
com.salesforce.androidsdk.ui.SalesforceR.java
com.salesforce.androidsdk.ui.SalesforceServerRadioButton.java
com.salesforce.androidsdk.ui.ServerPickerActivity.java
com.salesforce.androidsdk.ui.sfhybrid.SalesforceDroidGapActivity.java
com.salesforce.androidsdk.ui.sfhybrid.SalesforceGapViewClient.java
com.salesforce.androidsdk.ui.sfnative.SalesforceActivity.java
com.salesforce.androidsdk.ui.sfnative.SalesforceExpandableListActivity.java
com.salesforce.androidsdk.ui.sfnative.SalesforceListActivity.java
com.salesforce.androidsdk.util.EventsListenerQueue.java
com.salesforce.androidsdk.util.EventsObservable.java
com.salesforce.androidsdk.util.EventsObserver.java
com.salesforce.androidsdk.util.ForceAppInstrumentationTestCase.java
com.salesforce.androidsdk.util.HybridInstrumentationTestCase.java
com.salesforce.androidsdk.util.JSTestCase.java
com.salesforce.androidsdk.util.JUnitReportTestRunner.java
com.salesforce.androidsdk.util.LogUtil.java
com.salesforce.androidsdk.util.NativeInstrumentationTestCase.java
com.salesforce.androidsdk.util.TimeLimitedTestRunner.java
com.salesforce.androidsdk.util.TokenRevocationReceiver.java
com.salesforce.androidsdk.util.UriFragmentParser.java
com.salesforce.androidsdk.util.UserSwitchReceiver.java
com.salesforce.samples.accounteditor.AccountEditorApp.java
com.salesforce.samples.accounteditor.KeyImpl.java
com.salesforce.samples.analyticsapp.AnalyticsApp.java
com.salesforce.samples.analyticsapp.GraphActivity.java
com.salesforce.samples.analyticsapp.KeyImpl.java
com.salesforce.samples.analyticsapp.MainActivity.java
com.salesforce.samples.analyticsapp.PieChart.java
com.salesforce.samples.contactexplorer.ContactExplorerApp.java
com.salesforce.samples.contactexplorer.KeyImpl.java
com.salesforce.samples.hybridfileexplorer.HybridFileExplorerApp.java
com.salesforce.samples.hybridfileexplorer.KeyImpl.java
com.salesforce.samples.smartstoreexplorer.KeyImpl.java
com.salesforce.samples.smartstoreexplorer.SmartStoreExplorerApp.java
com.salesforce.samples.vfconnector.KeyImpl.java
com.salesforce.samples.vfconnector.VFConnectorApp.java