@Override
 public void setAdapter(ListAdapter adapter) {
   if (adapter == null) {
     mAdapter = null;
   } else if (mForceHeaderListAdapter
       || mHeaderViewInfos.size() > 0
       || mFooterViewInfos.size() > 0) {
     mAdapter =
         new HeaderViewListAdapter(
             mHeaderViewInfos, mFooterViewInfos, adapter, mListAdapterCallback);
   } else {
     mAdapter = new ListAdapterWrapper(adapter, mListAdapterCallback);
   }
   if (mAdapter != null) {
     mAdapterHasStableIds = mAdapter.hasStableIds();
     if (mChoiceMode != CHOICE_MODE_NONE && mAdapterHasStableIds && mCheckedIdStates == null) {
       mCheckedIdStates = new LongSparseArray<Integer>();
     }
   }
   if (mCheckStates != null) {
     mCheckStates.clear();
   }
   if (mCheckedIdStates != null) {
     mCheckedIdStates.clear();
   }
   super.setAdapter(mAdapter);
 }
 @Override
 public void clearChoices() {
   if (mCheckStates != null) {
     mCheckStates.clear();
   }
   if (mCheckedIdStates != null) {
     mCheckedIdStates.clear();
   }
   mCheckedItemCount = 0;
 }
 @Override
 public boolean performItemClick(View view, int position, long id) {
   boolean handled = false;
   boolean dispatchItemClick = true;
   if (mChoiceMode != CHOICE_MODE_NONE) {
     handled = true;
     boolean checkedStateChanged = false;
     if (mChoiceMode == CHOICE_MODE_MULTIPLE
         || mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL && mChoiceActionMode != null) {
       boolean newValue = !mCheckStates.get(position, false);
       mCheckStates.put(position, newValue);
       if (mCheckedIdStates != null && mAdapter.hasStableIds()) {
         if (newValue) {
           mCheckedIdStates.put(mAdapter.getItemId(position), position);
         } else {
           mCheckedIdStates.delete(mAdapter.getItemId(position));
         }
       }
       if (newValue) {
         mCheckedItemCount++;
       } else {
         mCheckedItemCount--;
       }
       if (mChoiceActionMode != null) {
         mMultiChoiceModeCallback.onItemCheckedStateChanged(
             mChoiceActionMode, position, id, newValue);
         dispatchItemClick = false;
       }
       checkedStateChanged = true;
     } else if (mChoiceMode == CHOICE_MODE_SINGLE) {
       boolean newValue = !mCheckStates.get(position, false);
       if (newValue) {
         mCheckStates.clear();
         mCheckStates.put(position, true);
         if (mCheckedIdStates != null && mAdapter.hasStableIds()) {
           mCheckedIdStates.clear();
           mCheckedIdStates.put(mAdapter.getItemId(position), position);
         }
         mCheckedItemCount = 1;
       } else if (mCheckStates.size() == 0 || !mCheckStates.valueAt(0)) {
         mCheckedItemCount = 0;
       }
       checkedStateChanged = true;
     }
     if (checkedStateChanged) {
       updateOnScreenCheckedViews();
     }
   }
   if (dispatchItemClick) {
     handled |= super.performItemClick(view, position, id);
   }
   return handled;
 }
 @Override
 public void setItemChecked(int position, boolean value) {
   if (mChoiceMode == CHOICE_MODE_NONE) {
     return;
   }
   if (value && mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL && mChoiceActionMode == null) {
     mChoiceActionMode = startActionMode(mMultiChoiceModeCallback);
   }
   if (mChoiceMode == CHOICE_MODE_MULTIPLE || mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL) {
     boolean oldValue = mCheckStates.get(position);
     mCheckStates.put(position, value);
     if (mCheckedIdStates != null && mAdapter.hasStableIds()) {
       if (value) {
         mCheckedIdStates.put(mAdapter.getItemId(position), position);
       } else {
         mCheckedIdStates.delete(mAdapter.getItemId(position));
       }
     }
     if (oldValue != value) {
       if (value) {
         mCheckedItemCount++;
       } else {
         mCheckedItemCount--;
       }
     }
     if (mChoiceActionMode != null) {
       final long id = mAdapter.getItemId(position);
       mMultiChoiceModeCallback.onItemCheckedStateChanged(mChoiceActionMode, position, id, value);
     }
   } else {
     boolean updateIds = mCheckedIdStates != null && mAdapter.hasStableIds();
     if (value || isItemChecked(position)) {
       mCheckStates.clear();
       if (updateIds) {
         mCheckedIdStates.clear();
       }
     }
     if (value) {
       mCheckStates.put(position, true);
       if (updateIds) {
         mCheckedIdStates.put(mAdapter.getItemId(position), position);
       }
       mCheckedItemCount = 1;
     } else if (mCheckStates.size() == 0 || !mCheckStates.valueAt(0)) {
       mCheckedItemCount = 0;
     }
   }
   updateOnScreenCheckedViews();
 }
 @Override
 public void invalidate() {
   mHeaderViews.clear();
 }
  /** Executed when service is started by intent */
  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
    Log.d(Constants.TAG, "PassphraseCacheService.onStartCommand()");

    if (intent == null || intent.getAction() == null) {
      updateService();
      return START_STICKY;
    }

    String action = intent.getAction();
    switch (action) {
      case ACTION_PASSPHRASE_CACHE_ADD:
        {
          long masterKeyId = intent.getLongExtra(EXTRA_KEY_ID, -1);
          long subKeyId = intent.getLongExtra(EXTRA_SUBKEY_ID, -1);
          long timeoutTtl = intent.getIntExtra(EXTRA_TTL, DEFAULT_TTL);

          Passphrase passphrase = intent.getParcelableExtra(EXTRA_PASSPHRASE);
          String primaryUserID = intent.getStringExtra(EXTRA_USER_ID);

          Log.d(
              Constants.TAG,
              "PassphraseCacheService: Received ACTION_PASSPHRASE_CACHE_ADD intent in onStartCommand() with masterkeyId: "
                  + masterKeyId
                  + ", subKeyId: "
                  + subKeyId
                  + ", ttl: "
                  + timeoutTtl
                  + ", usrId: "
                  + primaryUserID);

          // if we don't cache by specific subkey id, or the requested subkey is the master key,
          // just add master key id to the cache, otherwise, add this specific subkey to the cache
          long referenceKeyId =
              Preferences.getPreferences(mContext).getPassphraseCacheSubs()
                  ? subKeyId
                  : masterKeyId;

          CachedPassphrase cachedPassphrase;
          if (timeoutTtl == 0L) {
            cachedPassphrase = CachedPassphrase.getPassphraseLock(passphrase, primaryUserID);
          } else if (timeoutTtl >= Integer.MAX_VALUE) {
            cachedPassphrase = CachedPassphrase.getPassphraseNoTimeout(passphrase, primaryUserID);
          } else {
            cachedPassphrase =
                CachedPassphrase.getPassphraseTtlTimeout(passphrase, primaryUserID, timeoutTtl);

            long triggerTime = new Date().getTime() + (timeoutTtl * 1000);
            // register new alarm with keyId for this passphrase
            AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
            am.set(AlarmManager.RTC_WAKEUP, triggerTime, buildIntent(this, referenceKeyId));
          }

          mPassphraseCache.put(referenceKeyId, cachedPassphrase);

          break;
        }
      case ACTION_PASSPHRASE_CACHE_GET:
        {
          long masterKeyId = intent.getLongExtra(EXTRA_KEY_ID, Constants.key.symmetric);
          long subKeyId = intent.getLongExtra(EXTRA_SUBKEY_ID, Constants.key.symmetric);
          Messenger messenger = intent.getParcelableExtra(EXTRA_MESSENGER);

          Message msg = Message.obtain();
          try {
            // If only one of these is symmetric, error out!
            if (masterKeyId == Constants.key.symmetric ^ subKeyId == Constants.key.symmetric) {
              Log.e(
                  Constants.TAG,
                  "PassphraseCacheService: Bad request, missing masterKeyId or subKeyId!");
              msg.what = MSG_PASSPHRASE_CACHE_GET_KEY_NOT_FOUND;
            } else {
              Passphrase passphrase = getCachedPassphraseImpl(masterKeyId, subKeyId);
              msg.what = MSG_PASSPHRASE_CACHE_GET_OKAY;
              Bundle bundle = new Bundle();
              bundle.putParcelable(EXTRA_PASSPHRASE, passphrase);
              msg.setData(bundle);
            }
          } catch (ProviderHelper.NotFoundException e) {
            Log.e(
                Constants.TAG, "PassphraseCacheService: Passphrase for unknown key was requested!");
            msg.what = MSG_PASSPHRASE_CACHE_GET_KEY_NOT_FOUND;
          }

          try {
            messenger.send(msg);
          } catch (RemoteException e) {
            Log.e(Constants.TAG, "PassphraseCacheService: Sending message failed", e);
          }
          break;
        }
      case ACTION_PASSPHRASE_CACHE_CLEAR:
        {
          AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);

          if (intent.hasExtra(EXTRA_SUBKEY_ID) && intent.hasExtra(EXTRA_KEY_ID)) {

            long referenceKeyId;
            if (Preferences.getPreferences(mContext).getPassphraseCacheSubs()) {
              referenceKeyId = intent.getLongExtra(EXTRA_SUBKEY_ID, 0L);
            } else {
              referenceKeyId = intent.getLongExtra(EXTRA_KEY_ID, 0L);
            }
            // Stop specific ttl alarm and
            am.cancel(buildIntent(this, referenceKeyId));
            mPassphraseCache.delete(referenceKeyId);

          } else {

            // Stop all ttl alarms
            for (int i = 0; i < mPassphraseCache.size(); i++) {
              CachedPassphrase cachedPassphrase = mPassphraseCache.valueAt(i);
              if (cachedPassphrase.mTimeoutMode == TimeoutMode.TTL) {
                am.cancel(buildIntent(this, mPassphraseCache.keyAt(i)));
              }
            }
            mPassphraseCache.clear();
          }
          break;
        }
      default:
        {
          Log.e(Constants.TAG, "PassphraseCacheService: Intent or Intent Action not supported!");
          break;
        }
    }

    updateService();

    return START_STICKY;
  }