Android Open Source - force_analytics_example Passcode Manager






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  w  w . j  a  va2s. c  o  m
 * 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.security;

import java.io.File;
import java.io.FilenameFilter;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Handler;
import android.util.Log;

import com.salesforce.androidsdk.accounts.UserAccount;
import com.salesforce.androidsdk.app.SalesforceSDKManager;
import com.salesforce.androidsdk.app.UUIDManager;
import com.salesforce.androidsdk.util.EventsObservable;
import com.salesforce.androidsdk.util.EventsObservable.EventType;

/**
 * This class manages the inactivity timeout, and keeps track of if the UI should locked etc.
 *
 * @author wmathurin
 * @author bhariharan
 */
public class PasscodeManager  {

  // UUID keys
  private static final String VKEY = "vkey";
  private static final String VSUFFIX = "vsuffix";
  private static final String VPREFIX = "vprefix";
  private static final String EKEY = "ekey";
  private static final String ESUFFIX = "esuffix";
  private static final String EPREFIX = "eprefix";
  
    // Default min passcode length
    public static final int MIN_PASSCODE_LENGTH = 4;

    // Key in preference for the passcode
    private static final String KEY_PASSCODE ="passcode";

    // Private preference where we stored the passcode (hashed)
    private static final String PASSCODE_PREF_NAME = "user";

    // Private preference where we stored the org settings.
    private static final String MOBILE_POLICY_PREF = "mobile_policy";

    // Key in preference for the access timeout.
    private static final String KEY_TIMEOUT = "access_timeout";

    // Key in preference for the passcode length.
    private static final String KEY_PASSCODE_LENGTH = "passcode_length";

    // Request code used to start passcode activity
    public static final int PASSCODE_REQUEST_CODE = 777;

    // Key used to specify that a longer passcode needs to be created.
    public static final String CHANGE_PASSCODE_KEY = "change_passcode";

    // this is a hash of the passcode to be used as part of the key to encrypt/decrypt oauth tokens
    // It's using a different salt/key than the one used to verify the entry
    private String passcodeHash;

    // Misc
    private HashConfig verificationHashConfig;
    private HashConfig encryptionHashConfig;
    private int failedPasscodeAttempts;
    private Activity frontActivity;
    private Handler handler;
    private long lastActivity;
    private boolean locked;
    private int timeoutMs;
    private int minPasscodeLength;
    private LockChecker lockChecker;

    /**
     * Parameterized constructor.
     *
     * @param ctx Context.
     * @param verificationHashConfig Verification HashConfig.
     * @param encryptionHashConfig Encryption HashConfig.
     */
   public PasscodeManager(Context ctx) {
     this(ctx,
       new HashConfig(UUIDManager.getUuId(VPREFIX),
           UUIDManager.getUuId(VSUFFIX), UUIDManager.getUuId(VKEY)),
       new HashConfig(UUIDManager.getUuId(EPREFIX),
           UUIDManager.getUuId(ESUFFIX), UUIDManager.getUuId(EKEY)));
   }

   public PasscodeManager(Context ctx, HashConfig verificationHashConfig,
       HashConfig encryptionHashConfig) {
       this.minPasscodeLength = MIN_PASSCODE_LENGTH;
       this.lastActivity = now();
       this.verificationHashConfig = verificationHashConfig;
       this.encryptionHashConfig = encryptionHashConfig;
       readMobilePolicy(ctx);

       // Locked at app startup if you're authenticated.
       this.locked = true;
       lockChecker = new LockChecker(); 
   }

   /**
    * Returns the timeout value for the specified account.
    *
    * @param account UserAccount instance.
    * @return Timeout value.
    */
     public int getTimeoutMsForOrg(UserAccount account) {
       if (account == null) {
         return 0;
       }
       final Context context = SalesforceSDKManager.getInstance().getAppContext();
        final SharedPreferences sp = context.getSharedPreferences(MOBILE_POLICY_PREF
            + account.getOrgLevelFilenameSuffix(), Context.MODE_PRIVATE);
        return sp.getInt(KEY_TIMEOUT, 0);
     }

    /**
     * Returns the minimum passcode length for the specified account.
     *
     * @param account UserAccount instance.
     * @return Minimum passcode length.
     */
    public int getPasscodeLengthForOrg(UserAccount account) {
      if (account == null) {
        return MIN_PASSCODE_LENGTH;
      }
      final Context context = SalesforceSDKManager.getInstance().getAppContext();
        final SharedPreferences sp = context.getSharedPreferences(MOBILE_POLICY_PREF
            + account.getOrgLevelFilenameSuffix(), Context.MODE_PRIVATE);
        return sp.getInt(KEY_PASSCODE_LENGTH, MIN_PASSCODE_LENGTH);
    }

    /**
     * Stores the mobile policy for the specified account.
     *
     * @param account UserAccount instance.
     * @param timeout Timeout value, in ms.
     * @param passLen Minimum passcode length.
     */
    public void storeMobilePolicyForOrg(UserAccount account, int timeout, int passLen) {
      if (account == null) {
        return;
      }
      final Context context = SalesforceSDKManager.getInstance().getAppContext();
        final SharedPreferences sp = context.getSharedPreferences(MOBILE_POLICY_PREF
            + account.getOrgLevelFilenameSuffix(), Context.MODE_PRIVATE);
        final Editor e = sp.edit();
        e.putInt(KEY_TIMEOUT, timeout);
        e.putInt(KEY_PASSCODE_LENGTH, passLen);
        e.commit();
    }

    /**
     * Stores the mobile policy in a private file.
     *
     * @param context Context.
     */
    private void storeMobilePolicy(Context context) {

        // Context will be null only in test runs.
        if (context != null) {
            final SharedPreferences sp = context.getSharedPreferences(MOBILE_POLICY_PREF,
                Context.MODE_PRIVATE);
            Editor e = sp.edit();
            e.putInt(KEY_TIMEOUT, timeoutMs);
            e.putInt(KEY_PASSCODE_LENGTH, minPasscodeLength);
            e.commit();
        }
    }

    /**
     * Reads the mobile policy from a private file.
     *
     * @param context Context.
     */
    private void readMobilePolicy(Context context) {

        // Context will be null only in test runs.
        if (context != null) {
            final SharedPreferences sp = context.getSharedPreferences(MOBILE_POLICY_PREF,
                Context.MODE_PRIVATE);
            if (!sp.contains(KEY_TIMEOUT) || !sp.contains(KEY_PASSCODE_LENGTH)) {
                timeoutMs = 0;
                minPasscodeLength = MIN_PASSCODE_LENGTH;
                storeMobilePolicy(context);
                return;
            }
            timeoutMs = sp.getInt(KEY_TIMEOUT, 0);
            minPasscodeLength = sp.getInt(KEY_PASSCODE_LENGTH, MIN_PASSCODE_LENGTH);
        }
    }

    /**
     * Reset this passcode manager: delete stored passcode and reset fields to their starting value
     */
    public void reset(Context ctx) {

      // Deletes the underlying org policy files for all orgs.
      final String sharedPrefPath = ctx.getApplicationInfo().dataDir + "/shared_prefs";
      final File dir = new File(sharedPrefPath);
      final PasscodeFileFilter fileFilter = new PasscodeFileFilter();
      for (final File file : dir.listFiles()) {
        if (file != null && fileFilter.accept(dir, file.getName())) {
          file.delete();
        }
      }
      lastActivity = now();
        locked = true;
        failedPasscodeAttempts = 0;
        passcodeHash = null;
        SharedPreferences sp = ctx.getSharedPreferences(PASSCODE_PREF_NAME,
            Context.MODE_PRIVATE);
        Editor e = sp.edit();
        e.remove(KEY_PASSCODE);
        e.commit();
        timeoutMs = 0;
        minPasscodeLength = MIN_PASSCODE_LENGTH;
        storeMobilePolicy(ctx);
        handler = null;
    }

    /**
     * Resets the passcode policies for a particular org upon logout.
     *
     * @param context Context.
     * @param account User account.
     */
    public void reset(Context context, UserAccount account) {
      if (account == null) {
        return;
      }
        final SharedPreferences sp = context.getSharedPreferences(MOBILE_POLICY_PREF
            + account.getOrgLevelFilenameSuffix(), Context.MODE_PRIVATE);
        final Editor e = sp.edit();
        e.clear();
        e.commit();
    }

    /**
     * Enable/disable passcode screen.
     */
    public void setEnabled(boolean enabled) {
        if (enabled) {
            handler = new Handler();
            handler.postDelayed(lockChecker, 20 * 1000);
        } else {
            if (handler != null) {
                handler.removeCallbacks(lockChecker);
            }
            handler = null;
        }
    }

    /**
     * @return true if passcode manager is enabled.
     */
    public boolean isEnabled() {
        return (handler != null);
    }

    /**
     * @return the new failure count
     */
    public int addFailedPasscodeAttempt() {
        return ++failedPasscodeAttempts;
    }

    /**
     * @param ctx
     * @param passcode
     * @return true if passcode matches the one stored (hashed) in private preference
     */
    public boolean check(Context ctx, String passcode) {
        SharedPreferences sp = ctx.getSharedPreferences(PASSCODE_PREF_NAME, Context.MODE_PRIVATE);
        String hashedPasscode = sp.getString(KEY_PASSCODE, null);
        hashedPasscode = Encryptor.removeNewLine(hashedPasscode);
        if (hashedPasscode != null) {
            return hashedPasscode.equals(hashForVerification(passcode));
        }

        /*
         * If the stored passcode hash is null, there is no passcode.
         */
        return true;
    }

    /**
     * Store the given passcode (hashed) in private preference
     * @param ctx
     * @param passcode
     */
    public void store(Context ctx, String passcode) {
        SharedPreferences sp = ctx.getSharedPreferences(PASSCODE_PREF_NAME, Context.MODE_PRIVATE);
        Editor e = sp.edit();
        e.putString(KEY_PASSCODE, hashForVerification(passcode));
        e.commit();
    }

    /**
     * @param ctx
     * @return true if passcode was already created
     */
    public boolean hasStoredPasscode(Context ctx) {
        SharedPreferences sp = ctx.getSharedPreferences(PASSCODE_PREF_NAME, Context.MODE_PRIVATE);
        return sp.contains(KEY_PASSCODE);
    }

    /**
     * @return number of failed passcode attempts
     */
    public int getFailedPasscodeAttempts() {
        return failedPasscodeAttempts;
    }

    /**
     * @return a hash of the passcode that can be used for encrypting oauth tokens
     */
    public String getPasscodeHash() {
        return passcodeHash;
    }

    /**
     * Sets the passcode hash, used ONLY in tests.
     *
     * @param passcodeHash Passcode hash.
     */
    public void setPasscodeHash(String passcodeHash) {
      if (SalesforceSDKManager.getInstance().getIsTestRun()) {
          this.passcodeHash = passcodeHash;
      }
    }

    /**
     * @return true if locked
     */
    public boolean isLocked() {
        return timeoutMs > 0 && locked;
    }

    /**
     * @param ctx
     */
    public void lock(Context ctx) {
        locked = true;
        showLockActivity(ctx, false);
        EventsObservable.get().notifyEvent(EventType.AppLocked);
    }

    /**
     * @param newFrontActivity
     * @param registerActivity
     * @return
     */
    public boolean lockIfNeeded(Activity newFrontActivity, boolean registerActivity) {
        if (newFrontActivity != null)
            frontActivity = newFrontActivity;
        if (isEnabled() && (isLocked() || shouldLock())) {
            lock(frontActivity);
            return true;
        } else {
            if (registerActivity) updateLast();
            return false;
        }
    }

    /**
     * @param a
     */
    public void nolongerFrontActivity(Activity a) {
        if (frontActivity == a)
            frontActivity = null;
    }


    /**
     * To be called by passcode protected activity when being paused
     */
    public void onPause(Activity ctx) {

        // Disables passcode manager.
        setEnabled(false);
    }

    /**
     * To be called by passcode protected activity when being resumed
     * When passcode screen is about to be shown, false is returned, the activity will be resumed once
     * the user has successfully enter her passcode
     *
     * @return true if the resume should be allowed to continue and false otherwise
     */
    public boolean onResume(Activity ctx) {

        // Enables passcode manager.
        setEnabled(true);

        // Brings up passcode screen if needed.
        lockIfNeeded(ctx, true);

        // If locked, do nothing - when the app gets unlocked we will be back here.
        return !isLocked();
    }

    /**
     * To be called by passcode protected activity whenever there is a user interaction
     */
    public void recordUserInteraction() {
        updateLast();
    }

    /**
     * Called when the access timeout for the org changes.
     *
     * @param newTimeout New access timeout value.
     */
    public void setTimeoutMs(int newTimeout) {

        // Access timeout hasn't changed.
        if (timeoutMs == newTimeout) {
            return;
        }

        /*
         * Either access timeout has changed from one non-zero value to another,
         * which doesn't alter the passcode situation, or the app goes from
         * no passcode to passcode, which will trigger the passcode creation flow.
         */
        if (timeoutMs == 0 || (timeoutMs > 0 && newTimeout > 0)) {
            timeoutMs = newTimeout;
            storeMobilePolicy(SalesforceSDKManager.getInstance().getAppContext());
            return;
        }

        // Passcode to no passcode.
        timeoutMs = newTimeout;
        SalesforceSDKManager.getInstance().changePasscode(passcodeHash, null);
        reset(SalesforceSDKManager.getInstance().getAppContext());
    }

    public int getTimeoutMs() {
        return timeoutMs;
    }

    public int getMinPasscodeLength() {
        return minPasscodeLength;
    }

    public void setMinPasscodeLength(int minPasscodeLength) {
      if (minPasscodeLength > this.minPasscodeLength) {
            this.minPasscodeLength = minPasscodeLength;

            /*
             * This needs to happen only if a passcode exists, in order to trigger
             * the 'Change Passcode' flow. Otherwise, we simply need to update
             * the minimum length in memory. The 'Create Passcode' flow is
             * triggered later from OAuthWebviewHelper.
             */
            if (hasStoredPasscode(SalesforceSDKManager.getInstance().getAppContext())) {
            showLockActivity(SalesforceSDKManager.getInstance().getAppContext(),
                true);
            }
      }
        this.minPasscodeLength = minPasscodeLength;
        storeMobilePolicy(SalesforceSDKManager.getInstance().getAppContext());
    }

    public boolean shouldLock() {
        return timeoutMs > 0 && now() >= (lastActivity + timeoutMs);
    }

    public void showLockActivity(Context ctx, boolean changePasscodeFlow) {
        if (ctx == null) {
          return;
        }
        final Intent i = new Intent(ctx, SalesforceSDKManager.getInstance().getPasscodeActivity());
        i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        i.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
        i.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
        if (ctx == SalesforceSDKManager.getInstance().getAppContext()) {
            i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        }
        i.putExtra(CHANGE_PASSCODE_KEY, changePasscodeFlow);
        if (ctx instanceof Activity) {
            ((Activity) ctx).startActivityForResult(i, PASSCODE_REQUEST_CODE);
        } else {
            ctx.startActivity(i);
        }
    }

    public void unlock(String passcode) {
        locked = false;
        failedPasscodeAttempts = 0;
        passcodeHash = hashForEncryption(passcode);
        updateLast();
        EventsObservable.get().notifyEvent(EventType.AppUnlocked);
    }

    protected long now() {
        return System.currentTimeMillis();
    }

    private void updateLast() {
        lastActivity = now();
    }

    public String hashForVerification(String passcode) {
      return hash(passcode, verificationHashConfig);
    }
    
    public String hashForEncryption(String passcode) {
      return hash(passcode, encryptionHashConfig);
    }
    
    private String hash(String passcode, HashConfig hashConfig) {
        return Encryptor.hash(hashConfig.prefix + passcode + hashConfig.suffix, hashConfig.key);
    }

    /**
     * Thread checking periodically to see how much has elapsed since the last recorded activity
      * When that elapsed time exceed timeoutMs, it locks the app
      */
    private class LockChecker implements Runnable {
        public void run() {
            try {
              if (isEnabled()) {
                Log.d("LockChecker:run",  "isLocked:" + locked + " elapsedSinceLastActivity:" + ((now() - lastActivity)/1000) + " timeout:" + (timeoutMs / 1000));
              }
                if (!locked)
                    lockIfNeeded(null, false);
            } finally {
                if (handler != null) {
                    handler.postDelayed(this, 20 * 1000);
                }
            }
        }
    }

    /**
     * Key for hashing and salts to be preprended and appended to data to increase entropy.
     */
    public static class HashConfig {
        public final String prefix;
        public final String suffix;
        public final String key;
        public HashConfig(String prefix, String suffix, String key) {
            this.prefix = prefix;
            this.suffix = suffix;
            this.key = key;
        }
    }

    /**
     * This class acts as a filter to identify only the relevant passcode files.
     *
     * @author bhariharan
     */
    private static class PasscodeFileFilter implements FilenameFilter {

      private static final String PASSCODE_FILE_PREFIX = MOBILE_POLICY_PREF + "_";

    @Override
    public boolean accept(File dir, String filename) {
      if (filename != null && filename.startsWith(PASSCODE_FILE_PREFIX)) {
        return true;
      }
      return false;
    }
    }
}




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