/** * Update prefs that depend on home panels state. * * <p>This includes the prefs that keep track of whether bookmarks or history are enabled, which * are used to control the visibility of the corresponding menu items. */ private void updatePrefsFromConfig(JSONArray panelsArray) { final SharedPreferences prefs = GeckoSharedPrefs.forProfile(mContext); if (!prefs.contains(HomeConfig.PREF_KEY_BOOKMARKS_PANEL_ENABLED) || !prefs.contains(HomeConfig.PREF_KEY_HISTORY_PANEL_ENABLED)) { final String bookmarkType = PanelType.BOOKMARKS.toString(); final String historyType = PanelType.COMBINED_HISTORY.toString(); try { for (int i = 0; i < panelsArray.length(); i++) { final JSONObject panelObj = panelsArray.getJSONObject(i); final String panelType = panelObj.optString(PanelConfig.JSON_KEY_TYPE, null); if (panelType == null) { break; } final boolean isDisabled = panelObj.optBoolean(PanelConfig.JSON_KEY_DISABLED, false); if (bookmarkType.equals(panelType)) { prefs .edit() .putBoolean(HomeConfig.PREF_KEY_BOOKMARKS_PANEL_ENABLED, !isDisabled) .apply(); } else if (historyType.equals(panelType)) { prefs.edit().putBoolean(HomeConfig.PREF_KEY_HISTORY_PANEL_ENABLED, !isDisabled).apply(); } } } catch (JSONException e) { Log.e(LOGTAG, "Error fetching panel from config to update prefs"); } } }
private void saveToPrefs() { GeckoSharedPrefs.forProfile(mApplication) .edit() .putString(PREFS_URL, mHeaderURL) .putString(PREFS_COLOR, mColor) .apply(); // Let's keep the saved data in sync. mSavedURL = mHeaderURL; mSavedColor = mColor; }
public CombinedHistoryAdapter(Context context, int savedParentIndex) { super(); this.context = context; sectionHeaders = new SparseArray<>(); // This races when multiple Fragments are created. That's okay: one // will win, and thereafter, all will be okay. If we create and then // drop an instance the shared SharedPreferences backing all the // instances will maintain the state for us. Since everything happens on // the UI thread, this doesn't even need to be volatile. if (sState == null) { sState = new RemoteTabsExpandableListState(GeckoSharedPrefs.forProfile(context)); } remoteClientIndexOfParent = savedParentIndex; }
public void testHiddenSites() { resources.setSuggestedSitesResource(generateSites(6)); List<String> visibleUrls = new ArrayList<String>(3); visibleUrls.add("url3"); visibleUrls.add("url4"); visibleUrls.add("url5"); List<String> hiddenUrls = new ArrayList<String>(3); hiddenUrls.add("url0"); hiddenUrls.add("url1"); hiddenUrls.add("url2"); // Add mocked hidden sites to SharedPreferences. StringBuilder hiddenUrlBuilder = new StringBuilder(); for (String s : hiddenUrls) { hiddenUrlBuilder.append(" "); hiddenUrlBuilder.append(Uri.encode(s)); } final String hiddenPref = hiddenUrlBuilder.toString(); GeckoSharedPrefs.forProfile(context) .edit() .putString(SuggestedSites.PREF_SUGGESTED_SITES_HIDDEN, hiddenPref) .commit(); Cursor c = new SuggestedSites(context).get(DEFAULT_LIMIT); assertEquals(Math.min(3, DEFAULT_LIMIT), c.getCount()); c.moveToPosition(-1); while (c.moveToNext()) { String url = c.getString(c.getColumnIndexOrThrow(BrowserContract.SuggestedSites.URL)); assertFalse(hiddenUrls.contains(url)); assertTrue(visibleUrls.contains(url)); } c.close(); }
private File createProfileDir() throws IOException { INIParser parser = GeckoProfileDirectories.getProfilesINI(mMozillaDir); // Salt the name of our requested profile String saltedName = GeckoProfileDirectories.saltProfileName(mName); File profileDir = new File(mMozillaDir, saltedName); while (profileDir.exists()) { saltedName = GeckoProfileDirectories.saltProfileName(mName); profileDir = new File(mMozillaDir, saltedName); } // Attempt to create the salted profile dir if (!profileDir.mkdirs()) { throw new IOException("Unable to create profile."); } Log.d(LOGTAG, "Created new profile dir."); // Now update profiles.ini // If this is the first time its created, we also add a General section // look for the first profile number that isn't taken yet int profileNum = 0; boolean isDefaultSet = false; INISection profileSection; while ((profileSection = parser.getSection("Profile" + profileNum)) != null) { profileNum++; if (profileSection.getProperty("Default") != null) { isDefaultSet = true; } } profileSection = new INISection("Profile" + profileNum); profileSection.setProperty("Name", mName); profileSection.setProperty("IsRelative", 1); profileSection.setProperty("Path", saltedName); if (parser.getSection("General") == null) { INISection generalSection = new INISection("General"); generalSection.setProperty("StartWithLastProfile", 1); parser.addSection(generalSection); } if (!isDefaultSet && !mIsWebAppProfile) { // only set as default if this is the first non-webapp // profile we're creating profileSection.setProperty("Default", 1); // We have no intention of stopping this session. The FIRSTRUN session // ends when the browsing session/activity has ended. All events // during firstrun will be tagged as FIRSTRUN. Telemetry.startUISession(TelemetryContract.Session.FIRSTRUN); } parser.addSection(profileSection); parser.write(); // Trigger init for non-webapp profiles. if (!mIsWebAppProfile) { enqueueInitialization(); } // Write out profile creation time, mirroring the logic in nsToolkitProfileService. try { FileOutputStream stream = new FileOutputStream(profileDir.getAbsolutePath() + File.separator + "times.json"); OutputStreamWriter writer = new OutputStreamWriter(stream, Charset.forName("UTF-8")); try { writer.append("{\"created\": " + System.currentTimeMillis() + "}\n"); } finally { writer.close(); } } catch (Exception e) { // Best-effort. Log.w(LOGTAG, "Couldn't write times.json.", e); } // Initialize pref flag for displaying the start pane for a new non-webapp profile. if (!mIsWebAppProfile) { final SharedPreferences prefs = GeckoSharedPrefs.forProfile(mApplicationContext); prefs.edit().putBoolean(BrowserApp.PREF_STARTPANE_ENABLED, true).apply(); } return profileDir; }
private SharedPreferences getSharedPreferences() { return GeckoSharedPrefs.forProfile(mContext); }
/** * Migrates JSON config data storage. * * @param context Context used to get shared preferences and create built-in panel. * @param jsonString String currently stored in preferences. * @return JSONArray array representing new set of panel configs. */ private static synchronized JSONArray maybePerformMigration(Context context, String jsonString) throws JSONException { // If the migration is already done, we're at the current version. if (sMigrationDone) { final JSONObject json = new JSONObject(jsonString); return json.getJSONArray(JSON_KEY_PANELS); } // Make sure we only do this version check once. sMigrationDone = true; final JSONArray originalJsonPanels; final int version; final SharedPreferences prefs = GeckoSharedPrefs.forProfile(context); if (prefs.contains(PREFS_CONFIG_KEY_OLD)) { // Our original implementation did not contain versioning, so this is implicitly version 0. originalJsonPanels = new JSONArray(jsonString); version = 0; } else { final JSONObject json = new JSONObject(jsonString); originalJsonPanels = json.getJSONArray(JSON_KEY_PANELS); version = json.getInt(JSON_KEY_VERSION); } if (version == VERSION) { return originalJsonPanels; } Log.d(LOGTAG, "Performing migration"); final JSONArray newJsonPanels = new JSONArray(); final SharedPreferences.Editor prefsEditor = prefs.edit(); for (int v = version + 1; v <= VERSION; v++) { Log.d(LOGTAG, "Migrating to version = " + v); switch (v) { case 1: // Add "Recent Tabs" panel final PanelConfig recentTabsConfig = createBuiltinPanelConfig(context, PanelType.RECENT_TABS); final JSONObject jsonRecentTabsConfig = recentTabsConfig.toJSON(); // Add the new panel to the front of the array on phones. if (!HardwareUtils.isTablet()) { newJsonPanels.put(jsonRecentTabsConfig); } // Copy the original panel configs. final int count = originalJsonPanels.length(); for (int i = 0; i < count; i++) { final JSONObject jsonPanelConfig = originalJsonPanels.getJSONObject(i); newJsonPanels.put(jsonPanelConfig); } // Add the new panel to the end of the array on tablets. if (HardwareUtils.isTablet()) { newJsonPanels.put(jsonRecentTabsConfig); } // Remove the old pref key. prefsEditor.remove(PREFS_CONFIG_KEY_OLD); break; } } // Save the new panel config and the new version number. final JSONObject newJson = new JSONObject(); newJson.put(JSON_KEY_PANELS, newJsonPanels); newJson.put(JSON_KEY_VERSION, VERSION); prefsEditor.putString(PREFS_CONFIG_KEY, newJson.toString()); prefsEditor.commit(); return newJsonPanels; }
private void loadFromPrefs() { SharedPreferences prefs = GeckoSharedPrefs.forProfile(mApplication); mSavedURL = prefs.getString(PREFS_URL, null); mSavedColor = prefs.getString(PREFS_COLOR, null); }
/** Clear the data stored in preferences for fast path loading during startup */ private void clearPrefs() { GeckoSharedPrefs.forProfile(mApplication).edit().remove(PREFS_URL).remove(PREFS_COLOR).apply(); }
/** * Migrates JSON config data storage. * * @param context Context used to get shared preferences and create built-in panel. * @param jsonString String currently stored in preferences. * @return JSONArray array representing new set of panel configs. */ private static synchronized JSONArray maybePerformMigration(Context context, String jsonString) throws JSONException { // If the migration is already done, we're at the current version. if (sMigrationDone) { final JSONObject json = new JSONObject(jsonString); return json.getJSONArray(JSON_KEY_PANELS); } // Make sure we only do this version check once. sMigrationDone = true; JSONArray jsonPanels; final int version; final SharedPreferences prefs = GeckoSharedPrefs.forProfile(context); if (prefs.contains(PREFS_CONFIG_KEY_OLD)) { // Our original implementation did not contain versioning, so this is implicitly version 0. jsonPanels = new JSONArray(jsonString); version = 0; } else { final JSONObject json = new JSONObject(jsonString); jsonPanels = json.getJSONArray(JSON_KEY_PANELS); version = json.getInt(JSON_KEY_VERSION); } if (version == VERSION) { return jsonPanels; } Log.d(LOGTAG, "Performing migration"); final SharedPreferences.Editor prefsEditor = prefs.edit(); for (int v = version + 1; v <= VERSION; v++) { Log.d(LOGTAG, "Migrating to version = " + v); switch (v) { case 1: // Add "Recent Tabs" panel. addBuiltinPanelConfig( context, jsonPanels, PanelType.RECENT_TABS, Position.FRONT, Position.BACK); // Remove the old pref key. prefsEditor.remove(PREFS_CONFIG_KEY_OLD); break; case 2: // Add "Remote Tabs"/"Synced Tabs" panel. addBuiltinPanelConfig( context, jsonPanels, PanelType.DEPRECATED_REMOTE_TABS, Position.FRONT, Position.BACK); break; case 3: // Add the "Reading List" panel if it does not exist. At one time, // the Reading List panel was shown only to devices that were not // considered "low memory". Now, we expose the panel to all devices. // This migration should only occur for "low memory" devices. // Note: This will not agree with the default configuration, which // has DEPRECATED_REMOTE_TABS after READING_LIST on some devices. if (!readingListPanelExists(jsonPanels)) { addBuiltinPanelConfig( context, jsonPanels, PanelType.READING_LIST, Position.BACK, Position.BACK); } break; case 4: // Combine the History and Sync panels. In order to minimize an unexpected reordering // of panels, we try to replace the History panel if it's visible, and fall back to // the Sync panel if that's visible. jsonPanels = combineHistoryAndSyncPanels(context, jsonPanels); break; case 5: // This is the fix for bug 1264136 where we lost track of the default panel during some // migrations. ensureDefaultPanelForV5(context, jsonPanels); break; } } // Save the new panel config and the new version number. final JSONObject newJson = new JSONObject(); newJson.put(JSON_KEY_PANELS, jsonPanels); newJson.put(JSON_KEY_VERSION, VERSION); prefsEditor.putString(PREFS_CONFIG_KEY, newJson.toString()); prefsEditor.apply(); return jsonPanels; }