com.facebook.stetho.inspector.protocol.module.DOMStorage.java Source code

Java tutorial

Introduction

Here is the source code for com.facebook.stetho.inspector.protocol.module.DOMStorage.java

Source

/*
 * Copyright (c) 2014-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */
//
// Copyright 2004-present Facebook. All Rights Reserved.

package com.facebook.stetho.inspector.protocol.module;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Build;
import com.facebook.stetho.inspector.console.CLog;
import com.facebook.stetho.inspector.domstorage.DOMStoragePeerManager;
import com.facebook.stetho.inspector.domstorage.SharedPreferencesHelper;
import com.facebook.stetho.inspector.jsonrpc.JsonRpcException;
import com.facebook.stetho.inspector.jsonrpc.JsonRpcPeer;
import com.facebook.stetho.inspector.jsonrpc.JsonRpcResult;
import com.facebook.stetho.inspector.protocol.ChromeDevtoolsDomain;
import com.facebook.stetho.inspector.protocol.ChromeDevtoolsMethod;
import com.facebook.stetho.json.ObjectMapper;
import com.facebook.stetho.json.annotation.JsonProperty;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

public class DOMStorage implements ChromeDevtoolsDomain {
    private final Context mContext;
    private final DOMStoragePeerManager mDOMStoragePeerManager;
    private final ObjectMapper mObjectMapper = new ObjectMapper();

    public DOMStorage(Context context) {
        mContext = context;
        mDOMStoragePeerManager = new DOMStoragePeerManager(context);
    }

    @ChromeDevtoolsMethod
    public void enable(JsonRpcPeer peer, JSONObject params) {
        mDOMStoragePeerManager.addPeer(peer);
    }

    @ChromeDevtoolsMethod
    public void disable(JsonRpcPeer peer, JSONObject params) {
        mDOMStoragePeerManager.removePeer(peer);
    }

    @ChromeDevtoolsMethod
    public JsonRpcResult getDOMStorageItems(JsonRpcPeer peer, JSONObject params) throws JSONException {
        StorageId storage = mObjectMapper.convertValue(params.getJSONObject("storageId"), StorageId.class);

        ArrayList<List<String>> entries = new ArrayList<List<String>>();
        String prefTag = storage.securityOrigin;
        if (storage.isLocalStorage) {
            SharedPreferences prefs = mContext.getSharedPreferences(prefTag, Context.MODE_PRIVATE);
            for (Map.Entry<String, ?> prefsEntry : prefs.getAll().entrySet()) {
                ArrayList<String> entry = new ArrayList<String>(2);
                entry.add(prefsEntry.getKey());
                entry.add(SharedPreferencesHelper.valueToString(prefsEntry.getValue()));
                entries.add(entry);
            }
        }

        GetDOMStorageItemsResult result = new GetDOMStorageItemsResult();
        result.entries = entries;
        return result;
    }

    @ChromeDevtoolsMethod
    public void setDOMStorageItem(JsonRpcPeer peer, JSONObject params) throws JSONException, JsonRpcException {
        StorageId storage = mObjectMapper.convertValue(params.getJSONObject("storageId"), StorageId.class);
        String key = params.getString("key");
        String value = params.getString("value");

        if (storage.isLocalStorage) {
            SharedPreferences prefs = mContext.getSharedPreferences(storage.securityOrigin, Context.MODE_PRIVATE);
            Object existingValue = prefs.getAll().get(key);
            try {
                if (existingValue == null) {
                    throw new DOMStorageAssignmentException(
                            "Unsupported: cannot add new key " + key + " due to lack of type inference");
                } else {
                    SharedPreferences.Editor editor = prefs.edit();
                    try {
                        assignByType(editor, key, SharedPreferencesHelper.valueFromString(value, existingValue));
                        editor.apply();
                    } catch (IllegalArgumentException e) {
                        throw new DOMStorageAssignmentException(
                                String.format(Locale.US, "Type mismatch setting %s to %s (expected %s)", key, value,
                                        existingValue.getClass().getSimpleName()));
                    }
                }
            } catch (DOMStorageAssignmentException e) {
                CLog.writeToConsole(mDOMStoragePeerManager, Console.MessageLevel.ERROR,
                        Console.MessageSource.STORAGE, e.getMessage());

                // Force the DevTools UI to refresh with the old value again (it assumes that the set
                // operation succeeded).  Note that we should be able to do this by throwing
                // JsonRpcException but the UI doesn't respect setDOMStorageItem failure.
                if (prefs.contains(key)) {
                    mDOMStoragePeerManager.signalItemUpdated(storage, key, value,
                            SharedPreferencesHelper.valueToString(existingValue));
                } else {
                    mDOMStoragePeerManager.signalItemRemoved(storage, key);
                }
            }
        }
    }

    @ChromeDevtoolsMethod
    public void removeDOMStorageItem(JsonRpcPeer peer, JSONObject params) throws JSONException {
        StorageId storage = mObjectMapper.convertValue(params.getJSONObject("storageId"), StorageId.class);
        String key = params.getString("key");

        if (storage.isLocalStorage) {
            SharedPreferences prefs = mContext.getSharedPreferences(storage.securityOrigin, Context.MODE_PRIVATE);
            prefs.edit().remove(key).apply();
        }
    }

    private static void assignByType(SharedPreferences.Editor editor, String key, Object value)
            throws IllegalArgumentException {
        if (value instanceof Integer) {
            editor.putInt(key, (Integer) value);
        } else if (value instanceof Long) {
            editor.putLong(key, (Long) value);
        } else if (value instanceof Float) {
            editor.putFloat(key, (Float) value);
        } else if (value instanceof Boolean) {
            editor.putBoolean(key, (Boolean) value);
        } else if (value instanceof String) {
            editor.putString(key, (String) value);
        } else if (value instanceof Set) {
            putStringSet(editor, key, (Set<String>) value);
        } else {
            throw new IllegalArgumentException("Unsupported type=" + value.getClass().getName());
        }
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private static void putStringSet(SharedPreferences.Editor editor, String key, Set<String> value) {
        editor.putStringSet(key, value);
    }

    public static class StorageId {
        @JsonProperty(required = true)
        public String securityOrigin;

        @JsonProperty(required = true)
        public boolean isLocalStorage;
    }

    private static class GetDOMStorageItemsResult implements JsonRpcResult {
        @JsonProperty(required = true)
        public List<List<String>> entries;
    }

    public static class DomStorageItemsClearedParams {
        @JsonProperty(required = true)
        public StorageId storageId;
    }

    public static class DomStorageItemRemovedParams {
        @JsonProperty(required = true)
        public StorageId storageId;

        @JsonProperty(required = true)
        public String key;
    }

    public static class DomStorageItemAddedParams {
        @JsonProperty(required = true)
        public StorageId storageId;

        @JsonProperty(required = true)
        public String key;

        @JsonProperty(required = true)
        public String newValue;
    }

    public static class DomStorageItemUpdatedParams {
        @JsonProperty(required = true)
        public StorageId storageId;

        @JsonProperty(required = true)
        public String key;

        @JsonProperty(required = true)
        public String oldValue;

        @JsonProperty(required = true)
        public String newValue;
    }

    /**
     * Exception thrown internally when we fail to honor {@link #setDOMStorageItem}.
     */
    private static class DOMStorageAssignmentException extends Exception {
        public DOMStorageAssignmentException(String message) {
            super(message);
        }
    }
}