| // Copyright 2020 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| package org.chromium.chrome.browser.tabpersistence; |
| |
| import android.content.Context; |
| |
| import androidx.annotation.VisibleForTesting; |
| |
| import org.chromium.base.ContextUtils; |
| import org.chromium.base.Log; |
| import org.chromium.base.StrictModeContext; |
| |
| import java.io.File; |
| |
| /** |
| * Manages the directory where tab state is saved. |
| * |
| * TODO(crbug.com/1097396): Deduplicate code between tabbed mode and custom tabs. |
| */ |
| public class TabStateDirectory { |
| private static final String TAG = "tabpersistence"; |
| |
| /** The name of the base directory where the state is saved. */ |
| private static final String BASE_STATE_FOLDER = "tabs"; |
| |
| /** The name of the directory where the state for tabbed mode is saved. */ |
| private static final String TABBED_MODE_DIRECTORY = "0"; |
| |
| /** The name of the directory where the state for custom tabs is saved. */ |
| public static final String CUSTOM_TABS_DIRECTORY = "custom_tabs"; |
| |
| /** Prevents two state directories from getting created simultaneously. */ |
| private static final Object TABBED_MODE_DIR_CREATION_LOCK = new Object(); |
| |
| /** Prevents two state directories from getting created simultaneously. */ |
| private static final Object CUSTOM_TABS_DIR_CREATION_LOCK = new Object(); |
| |
| private static File sTabbedModeStateDirectory; |
| private static File sCustomTabsStateDirectory; |
| |
| /** |
| * The folder where the state should be saved to. |
| * @return A file representing the directory that contains TabModelSelector states. |
| */ |
| public static File getOrCreateTabbedModeStateDirectory() { |
| synchronized (TABBED_MODE_DIR_CREATION_LOCK) { |
| if (sTabbedModeStateDirectory == null) { |
| sTabbedModeStateDirectory = |
| new File(getOrCreateBaseStateDirectory(), TABBED_MODE_DIRECTORY); |
| try (StrictModeContext ignored = StrictModeContext.allowDiskWrites()) { |
| if (!sTabbedModeStateDirectory.exists() |
| && !sTabbedModeStateDirectory.mkdirs()) { |
| Log.e(TAG, "Failed to create state folder: " + sTabbedModeStateDirectory); |
| } |
| } |
| } |
| } |
| return sTabbedModeStateDirectory; |
| } |
| |
| /** |
| * The folder where the state should be saved to. |
| * @return A file representing the directory that contains TabModelSelector states. |
| */ |
| public static File getOrCreateCustomTabModeStateDirectory() { |
| synchronized (CUSTOM_TABS_DIR_CREATION_LOCK) { |
| if (sCustomTabsStateDirectory == null) { |
| sCustomTabsStateDirectory = |
| new File(getOrCreateBaseStateDirectory(), CUSTOM_TABS_DIRECTORY); |
| try (StrictModeContext ignored = StrictModeContext.allowDiskWrites()) { |
| if (!sCustomTabsStateDirectory.exists() |
| && !sCustomTabsStateDirectory.mkdirs()) { |
| Log.e(TAG, "Failed to create state folder: " + sCustomTabsStateDirectory); |
| } |
| } |
| } |
| } |
| return sCustomTabsStateDirectory; |
| } |
| |
| private static class BaseStateDirectoryHolder { |
| // Not final for tests. |
| private static File sDirectory; |
| |
| static { |
| sDirectory = ContextUtils.getApplicationContext().getDir( |
| BASE_STATE_FOLDER, Context.MODE_PRIVATE); |
| } |
| } |
| |
| /** |
| * Directory containing all data for TabModels. Each subdirectory stores info about different |
| * TabModelSelectors, including metadata about each TabModel and TabStates for each of their |
| * tabs. |
| * |
| * @return The parent state directory. |
| */ |
| public static File getOrCreateBaseStateDirectory() { |
| return BaseStateDirectoryHolder.sDirectory; |
| } |
| |
| /** |
| * Sets where the base state directory is in tests. |
| */ |
| @VisibleForTesting |
| public static void setBaseStateDirectoryForTests(File directory) { |
| BaseStateDirectoryHolder.sDirectory = directory; |
| } |
| |
| @VisibleForTesting |
| public static void resetTabbedModeStateDirectoryForTesting() { |
| sTabbedModeStateDirectory = null; |
| } |
| } |