michael@0: /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: package org.mozilla.gecko.home; michael@0: michael@0: import static org.mozilla.gecko.home.HomeConfig.createBuiltinPanelConfig; michael@0: michael@0: import java.util.ArrayList; michael@0: import java.util.EnumSet; michael@0: import java.util.List; michael@0: import java.util.Locale; michael@0: michael@0: import org.json.JSONArray; michael@0: import org.json.JSONException; michael@0: import org.json.JSONObject; michael@0: import org.mozilla.gecko.GeckoSharedPrefs; michael@0: import org.mozilla.gecko.home.HomeConfig.HomeConfigBackend; michael@0: import org.mozilla.gecko.home.HomeConfig.OnReloadListener; michael@0: import org.mozilla.gecko.home.HomeConfig.PanelConfig; michael@0: import org.mozilla.gecko.home.HomeConfig.PanelType; michael@0: import org.mozilla.gecko.home.HomeConfig.State; michael@0: import org.mozilla.gecko.util.HardwareUtils; michael@0: michael@0: import android.content.BroadcastReceiver; michael@0: import android.content.Context; michael@0: import android.content.Intent; michael@0: import android.content.IntentFilter; michael@0: import android.content.SharedPreferences; michael@0: import android.content.SharedPreferences.OnSharedPreferenceChangeListener; michael@0: import android.support.v4.content.LocalBroadcastManager; michael@0: import android.text.TextUtils; michael@0: import android.util.Log; michael@0: michael@0: class HomeConfigPrefsBackend implements HomeConfigBackend { michael@0: private static final String LOGTAG = "GeckoHomeConfigBackend"; michael@0: michael@0: private static final String PREFS_CONFIG_KEY = "home_panels"; michael@0: private static final String PREFS_LOCALE_KEY = "home_locale"; michael@0: michael@0: private static final String RELOAD_BROADCAST = "HomeConfigPrefsBackend:Reload"; michael@0: michael@0: private final Context mContext; michael@0: private ReloadBroadcastReceiver mReloadBroadcastReceiver; michael@0: private OnReloadListener mReloadListener; michael@0: michael@0: public HomeConfigPrefsBackend(Context context) { michael@0: mContext = context; michael@0: } michael@0: michael@0: private SharedPreferences getSharedPreferences() { michael@0: return GeckoSharedPrefs.forProfile(mContext); michael@0: } michael@0: michael@0: private State loadDefaultConfig() { michael@0: final ArrayList panelConfigs = new ArrayList(); michael@0: michael@0: panelConfigs.add(createBuiltinPanelConfig(mContext, PanelType.TOP_SITES, michael@0: EnumSet.of(PanelConfig.Flags.DEFAULT_PANEL))); michael@0: michael@0: panelConfigs.add(createBuiltinPanelConfig(mContext, PanelType.BOOKMARKS)); michael@0: michael@0: // We disable reader mode support on low memory devices. Hence the michael@0: // reading list panel should not show up on such devices. michael@0: if (!HardwareUtils.isLowMemoryPlatform()) { michael@0: panelConfigs.add(createBuiltinPanelConfig(mContext, PanelType.READING_LIST)); michael@0: } michael@0: michael@0: final PanelConfig historyEntry = createBuiltinPanelConfig(mContext, PanelType.HISTORY); michael@0: michael@0: // On tablets, the history panel is the last. michael@0: // On phones, the history panel is the first one. michael@0: if (HardwareUtils.isTablet()) { michael@0: panelConfigs.add(historyEntry); michael@0: } else { michael@0: panelConfigs.add(0, historyEntry); michael@0: } michael@0: michael@0: return new State(panelConfigs, true); michael@0: } michael@0: michael@0: private State loadConfigFromString(String jsonString) { michael@0: final JSONArray jsonPanelConfigs; michael@0: try { michael@0: jsonPanelConfigs = new JSONArray(jsonString); michael@0: } catch (JSONException e) { michael@0: Log.e(LOGTAG, "Error loading the list of home panels from JSON prefs", e); michael@0: michael@0: // Fallback to default config michael@0: return loadDefaultConfig(); michael@0: } michael@0: michael@0: final ArrayList panelConfigs = new ArrayList(); michael@0: michael@0: final int count = jsonPanelConfigs.length(); michael@0: for (int i = 0; i < count; i++) { michael@0: try { michael@0: final JSONObject jsonPanelConfig = jsonPanelConfigs.getJSONObject(i); michael@0: final PanelConfig panelConfig = new PanelConfig(jsonPanelConfig); michael@0: panelConfigs.add(panelConfig); michael@0: } catch (Exception e) { michael@0: Log.e(LOGTAG, "Exception loading PanelConfig from JSON", e); michael@0: } michael@0: } michael@0: michael@0: return new State(panelConfigs, false); michael@0: } michael@0: michael@0: @Override michael@0: public State load() { michael@0: final SharedPreferences prefs = getSharedPreferences(); michael@0: final String jsonString = prefs.getString(PREFS_CONFIG_KEY, null); michael@0: michael@0: final State configState; michael@0: if (TextUtils.isEmpty(jsonString)) { michael@0: configState = loadDefaultConfig(); michael@0: } else { michael@0: configState = loadConfigFromString(jsonString); michael@0: } michael@0: michael@0: return configState; michael@0: } michael@0: michael@0: @Override michael@0: public void save(State configState) { michael@0: final SharedPreferences prefs = getSharedPreferences(); michael@0: final SharedPreferences.Editor editor = prefs.edit(); michael@0: michael@0: // No need to save the state to disk if it represents the default michael@0: // HomeConfig configuration. Simply force all existing HomeConfigLoader michael@0: // instances to refresh their contents. michael@0: if (!configState.isDefault()) { michael@0: final JSONArray jsonPanelConfigs = new JSONArray(); michael@0: michael@0: for (PanelConfig panelConfig : configState) { michael@0: try { michael@0: final JSONObject jsonPanelConfig = panelConfig.toJSON(); michael@0: jsonPanelConfigs.put(jsonPanelConfig); michael@0: } catch (Exception e) { michael@0: Log.e(LOGTAG, "Exception converting PanelConfig to JSON", e); michael@0: } michael@0: } michael@0: michael@0: editor.putString(PREFS_CONFIG_KEY, jsonPanelConfigs.toString()); michael@0: } michael@0: michael@0: editor.putString(PREFS_LOCALE_KEY, Locale.getDefault().toString()); michael@0: editor.commit(); michael@0: michael@0: // Trigger reload listeners on all live backend instances michael@0: sendReloadBroadcast(); michael@0: } michael@0: michael@0: @Override michael@0: public String getLocale() { michael@0: final SharedPreferences prefs = getSharedPreferences(); michael@0: michael@0: String locale = prefs.getString(PREFS_LOCALE_KEY, null); michael@0: if (locale == null) { michael@0: // Initialize config with the current locale michael@0: final String currentLocale = Locale.getDefault().toString(); michael@0: michael@0: final SharedPreferences.Editor editor = prefs.edit(); michael@0: editor.putString(PREFS_LOCALE_KEY, currentLocale); michael@0: editor.commit(); michael@0: michael@0: // If the user has saved HomeConfig before, return null this michael@0: // one time to trigger a refresh and ensure we use the michael@0: // correct locale for the saved state. For more context, michael@0: // see HomePanelsManager.onLocaleReady(). michael@0: if (!prefs.contains(PREFS_CONFIG_KEY)) { michael@0: locale = currentLocale; michael@0: } michael@0: } michael@0: michael@0: return locale; michael@0: } michael@0: michael@0: @Override michael@0: public void setOnReloadListener(OnReloadListener listener) { michael@0: if (mReloadListener != null) { michael@0: unregisterReloadReceiver(); michael@0: mReloadBroadcastReceiver = null; michael@0: } michael@0: michael@0: mReloadListener = listener; michael@0: michael@0: if (mReloadListener != null) { michael@0: mReloadBroadcastReceiver = new ReloadBroadcastReceiver(); michael@0: registerReloadReceiver(); michael@0: } michael@0: } michael@0: michael@0: private void sendReloadBroadcast() { michael@0: final LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(mContext); michael@0: final Intent reloadIntent = new Intent(RELOAD_BROADCAST); michael@0: lbm.sendBroadcast(reloadIntent); michael@0: } michael@0: michael@0: private void registerReloadReceiver() { michael@0: final LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(mContext); michael@0: lbm.registerReceiver(mReloadBroadcastReceiver, new IntentFilter(RELOAD_BROADCAST)); michael@0: } michael@0: michael@0: private void unregisterReloadReceiver() { michael@0: final LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(mContext); michael@0: lbm.unregisterReceiver(mReloadBroadcastReceiver); michael@0: } michael@0: michael@0: private class ReloadBroadcastReceiver extends BroadcastReceiver { michael@0: @Override michael@0: public void onReceive(Context context, Intent intent) { michael@0: mReloadListener.onReload(); michael@0: } michael@0: } michael@0: }