/* * Copyright 2010 Kevin Gaudin * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.acra.collector; import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; import android.support.annotation.NonNull; import org.acra.ACRA; import org.acra.ACRAConstants; import org.acra.ReportField; import org.acra.annotation.ReportsCrashes; import org.acra.builder.ReportBuilder; import org.acra.config.ACRAConfiguration; import org.acra.model.ComplexElement; import org.acra.model.Element; import org.acra.model.StringElement; import org.json.JSONException; import org.json.JSONObject; import java.util.Iterator; import java.util.Map; import java.util.TreeMap; import static org.acra.ACRA.LOG_TAG; /** * Collects the content (key/value pairs) of SharedPreferences, from the * application default preferences or any other preferences asked by the * application developer. */ final class SharedPreferencesCollector extends Collector { private final Context context; private final ACRAConfiguration config; private final SharedPreferences prefs; SharedPreferencesCollector(@NonNull Context context, @NonNull ACRAConfiguration config, SharedPreferences prefs) { super(ReportField.USER_EMAIL, ReportField.SHARED_PREFERENCES); this.context = context; this.config = config; this.prefs = prefs; } /** * Collects all key/value pairs in SharedPreferences. * The application default SharedPreferences are always * collected, and the developer can provide additional SharedPreferences * names in the {@link ReportsCrashes#additionalSharedPreferences()} * configuration item. * * @return the collected key/value pairs. */ @NonNull private Element collect() throws JSONException { final ComplexElement result = new ComplexElement(); // Include the default SharedPreferences final Map<String, SharedPreferences> sharedPrefs = new TreeMap<String, SharedPreferences>(); sharedPrefs.put("default", PreferenceManager.getDefaultSharedPreferences(context)); // Add in any additional SharedPreferences for (final String sharedPrefId : config.additionalSharedPreferences()) { sharedPrefs.put(sharedPrefId, context.getSharedPreferences(sharedPrefId, Context.MODE_PRIVATE)); } // Iterate over all included preference files and add the preferences from each. for (Map.Entry<String, SharedPreferences> entry : sharedPrefs.entrySet()) { final String sharedPrefId = entry.getKey(); final SharedPreferences prefs = entry.getValue(); final Map<String, ?> prefEntries = prefs.getAll(); // Show that we have no preferences saved for that preference file. if (prefEntries.isEmpty()) { result.put(sharedPrefId, "empty"); } else { for (final Iterator<String> iterator = prefEntries.keySet().iterator(); iterator.hasNext();){ if(filteredKey(iterator.next())){ iterator.remove(); } } result.put(sharedPrefId, new JSONObject(prefEntries)); } } return result; } /** * Checks if the key matches one of the patterns provided by the developer * to exclude some preferences from reports. * * @param key the name of the preference to be checked * @return true if the key has to be excluded from reports. */ private boolean filteredKey(@NonNull String key) { for (String regex : config.excludeMatchingSharedPreferencesKeys()) { if (key.matches(regex)) { return true; } } return false; } @NonNull @Override Element collect(ReportField reportField, ReportBuilder reportBuilder) { switch (reportField) { case USER_EMAIL: final String email = prefs.getString(ACRA.PREF_USER_EMAIL_ADDRESS, null); return email != null ? new StringElement(email) : ACRAConstants.NOT_AVAILABLE; case SHARED_PREFERENCES: try { return collect(); } catch (JSONException e) { ACRA.log.w(LOG_TAG, "Could not collect shared preferences", e); return ACRAConstants.NOT_AVAILABLE; } default: //will not happen if used correctly throw new IllegalArgumentException(); } } }