// 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();
}
}