// Copyright 2015 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.ntp; import org.chromium.chrome.browser.FrozenNativePage; import org.chromium.chrome.browser.NativePage; import org.chromium.chrome.browser.tab.Tab; import java.lang.ref.WeakReference; import java.util.ArrayList; /** * NativePageAssassin tracks recent tabs and freezes each native page when it hasn't been visible * for a while. This keeps hidden NativePages from using up precious memory. * * The NativePageAssassin is a singleton since having full knowledge of the user's hidden tabs -- * across all local instances of Chrome and all TabModels -- allows the NativePageAssassin to better * estimate which hidden tabs the user is likely to return to. * * Thread safety: this should only be accessed on the UI thread. */ public class NativePageAssassin { private static final NativePageAssassin sInstance = new NativePageAssassin(); /** * The number of hidden tabs to consider "recent". Any non-recent native page will be frozen. */ private static final int MAX_RECENT_TABS = 3; /** * The most recently hidden tabs, limited to MAX_RECENT_TABS elements, ordered from oldest to * newest. Visible tabs are not included in this list. */ private ArrayList<WeakReference<Tab>> mRecentTabs = new ArrayList<WeakReference<Tab>>( MAX_RECENT_TABS + 1); private NativePageAssassin() {} /** * @return The one and only NativePageAssassin. */ public static NativePageAssassin getInstance() { return sInstance; } /** * Call this whenever a tab is shown. * * @param tab The tab being shown. */ public void tabShown(Tab tab) { // Remove the tab from the list of recently hidden tabs. for (int i = 0; i < mRecentTabs.size(); i++) { Tab t = mRecentTabs.get(i).get(); if (t == tab) { mRecentTabs.remove(i); } } } /** * Call this whenever a tab is hidden. * * @param tab The tab being hidden. */ public void tabHidden(Tab tab) { mRecentTabs.add(new WeakReference<Tab>(tab)); // If a tab has just passed the threshold from "recent" to "not recent" and it's displaying // a native page, freeze the native page. if (mRecentTabs.size() <= MAX_RECENT_TABS) return; freeze(mRecentTabs.remove(0).get()); } /** * Freezes all hidden NativePages that aren't already frozen. */ public void freezeAllHiddenPages() { for (int i = 0; i < mRecentTabs.size(); i++) { freeze(mRecentTabs.get(i).get()); } mRecentTabs.clear(); } private void freeze(Tab tab) { if (tab == null) return; NativePage pageToFreeze = tab.getNativePage(); if (pageToFreeze == null || pageToFreeze instanceof FrozenNativePage || pageToFreeze.getView().getParent() != null) { return; } tab.freezeNativePage(); } }