All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.launchdarkly.sdk.android.SharedPrefsFlagStore Maven / Gradle / Ivy

package com.launchdarkly.sdk.android;

import android.annotation.SuppressLint;
import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Pair;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.google.gson.Gson;

import java.io.File;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

class SharedPrefsFlagStore implements FlagStore {

    private static final String SHARED_PREFS_BASE_KEY = "LaunchDarkly-";
    private final String prefsKey;
    private final Application application;
    private SharedPreferences sharedPreferences;
    private WeakReference listenerWeakReference;

    SharedPrefsFlagStore(@NonNull Application application, @NonNull String identifier) {
        this.application = application;
        this.prefsKey = SHARED_PREFS_BASE_KEY + identifier + "-flags";
        this.sharedPreferences = application.getSharedPreferences(prefsKey, Context.MODE_PRIVATE);
        this.listenerWeakReference = new WeakReference<>(null);
    }

    @SuppressLint("ApplySharedPref")
    @Override
    public void delete() {
        sharedPreferences.edit().clear().commit();
        sharedPreferences = null;

        File file = new File(application.getFilesDir().getParent() + "/shared_prefs/" + prefsKey + ".xml");
        LDConfig.LOG.i("Deleting SharedPrefs file:%s", file.getAbsolutePath());

        //noinspection ResultOfMethodCallIgnored
        file.delete();
    }

    @Override
    public void clear() {
        sharedPreferences.edit().clear().apply();
    }

    @Override
    public boolean containsKey(String key) {
        return sharedPreferences.contains(key);
    }

    @Nullable
    @Override
    public Flag getFlag(String flagKey) {
        return LDUtil.sharedPrefsGetGson(sharedPreferences, Flag.class, flagKey);
    }

    private Pair applyFlagUpdateNoCommit(@NonNull SharedPreferences.Editor editor, @NonNull FlagUpdate flagUpdate) {
        String flagKey = flagUpdate.flagToUpdate();
        if (flagKey == null) {
            return null;
        }
        Flag flag = getFlag(flagKey);
        Flag newFlag = flagUpdate.updateFlag(flag);
        if (flag != null && newFlag == null) {
            editor.remove(flagKey);
            return new Pair<>(flagKey, FlagStoreUpdateType.FLAG_DELETED);
        } else if (flag == null && newFlag != null) {
            String flagData = GsonCache.getGson().toJson(newFlag);
            editor.putString(flagKey, flagData);
            return new Pair<>(flagKey, FlagStoreUpdateType.FLAG_CREATED);
        } else if (flag != newFlag) {
            String flagData = GsonCache.getGson().toJson(newFlag);
            editor.putString(flagKey, flagData);
            return new Pair<>(flagKey, FlagStoreUpdateType.FLAG_UPDATED);
        }
        return null;
    }

    @Override
    public void applyFlagUpdate(FlagUpdate flagUpdate) {
        SharedPreferences.Editor editor = sharedPreferences.edit();
        Pair update = applyFlagUpdateNoCommit(editor, flagUpdate);
        editor.apply();
        StoreUpdatedListener storeUpdatedListener = listenerWeakReference.get();
        if (update != null && storeUpdatedListener != null) {
            storeUpdatedListener.onStoreUpdate(Collections.singletonList(new Pair<>(update.first, update.second)));
        }
    }

    private void informListenerOfUpdateList(List> updates) {
        StoreUpdatedListener storeUpdatedListener = listenerWeakReference.get();
        if (storeUpdatedListener != null) {
            storeUpdatedListener.onStoreUpdate(updates);
        }
    }

    @Override
    public void applyFlagUpdates(List flagUpdates) {
        SharedPreferences.Editor editor = sharedPreferences.edit();
        ArrayList> updates = new ArrayList<>();
        for (FlagUpdate flagUpdate : flagUpdates) {
            Pair update = applyFlagUpdateNoCommit(editor, flagUpdate);
            if (update != null) {
                updates.add(update);
            }
        }
        editor.apply();
        informListenerOfUpdateList(updates);
    }

    @Override
    public void clearAndApplyFlagUpdates(List newFlags) {
        Gson gson = GsonCache.getGson();
        Map cachedFlags = LDUtil.sharedPrefsGetAllGson(sharedPreferences, Flag.class);
        // here we explicitly copy the keySet()
        // this is because modifying a keySet() also modifies the underlying map
        // and we modify this further up to track changes
        Set clearedKeys = new HashSet<>(cachedFlags.keySet());
        SharedPreferences.Editor editor = sharedPreferences.edit();
        editor.clear();
        ArrayList> updates = new ArrayList<>();
        for (FlagUpdate flagUpdate : newFlags) {
            String flagKey = flagUpdate.flagToUpdate();
            if (flagKey == null) {
                continue;
            }
            Flag newFlag = flagUpdate.updateFlag(null);
            if (newFlag != null) {
                String flagData = gson.toJson(newFlag);
                editor.putString(flagKey, flagData);

                // track that this key has not been deleted
                clearedKeys.remove(flagKey);

                Flag cachedFlag = cachedFlags.get(flagKey);

                if (cachedFlag != null) {
                    Integer cv = cachedFlag.getVersion();
                    Integer nv = newFlag.getVersion();

                    if (!Objects.equals(cv, nv)) {
                        // only track updates if the versions of the flag has changed
                        updates.add(new Pair<>(flagKey, FlagStoreUpdateType.FLAG_UPDATED));
                    }
                    continue;
                }

                // Flag not present in cached flags so mark it as newly created
                updates.add(new Pair<>(flagKey, FlagStoreUpdateType.FLAG_CREATED));
            }
        }
        editor.apply();
        for (String clearedKey : clearedKeys) {
            updates.add(new Pair<>(clearedKey, FlagStoreUpdateType.FLAG_DELETED));
        }
        informListenerOfUpdateList(updates);
    }

    @Override
    public Collection getAllFlags() {
        return LDUtil.sharedPrefsGetAllGson(sharedPreferences, Flag.class).values();
    }

    @Override
    public void registerOnStoreUpdatedListener(StoreUpdatedListener storeUpdatedListener) {
        listenerWeakReference = new WeakReference<>(storeUpdatedListener);
    }

    @Override
    public void unregisterOnStoreUpdatedListener() {
        listenerWeakReference.clear();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy