| 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | package org.chromium.chrome.testshell; |
| 6 | |
| 7 | import android.content.Context; |
| 8 | import android.text.TextUtils; |
| 9 | |
| 10 | import org.chromium.base.ObserverList; |
| 11 | import org.chromium.chrome.browser.ChromeWebContentsDelegateAndroid; |
| 12 | import org.chromium.chrome.browser.ContentViewUtil; |
| 13 | import org.chromium.chrome.browser.TabBase; |
| 14 | import org.chromium.content.browser.ContentView; |
| 15 | import org.chromium.content.browser.LoadUrlParams; |
| 16 | import org.chromium.content.common.CleanupReference; |
| 17 | import org.chromium.ui.WindowAndroid; |
| 18 | |
| 19 | /** |
| 20 | * TestShell's implementation of a tab. This mirrors how Chrome for Android subclasses |
| 21 | * and extends {@link TabBase}. |
| 22 | */ |
| 23 | public class TestShellTab extends TabBase { |
| 24 | private ChromeWebContentsDelegateAndroid mWebContentsDelegate; |
| 25 | private ContentView mContentView; |
| 26 | private int mNativeTestShellTab; |
| 27 | private final ObserverList<TestShellTabObserver> mObservers = |
| 28 | new ObserverList<TestShellTabObserver>(); |
| 29 | |
| 30 | private CleanupReference mCleanupReference; |
| 31 | |
| 32 | // Tab state |
| 33 | private boolean mIsLoading = false; |
| 34 | |
| 35 | /** |
| 36 | * @param context The Context the view is running in. |
| 37 | * @param url The URL to start this tab with. |
| 38 | * @param window The WindowAndroid should represent this tab. |
| 39 | */ |
| 40 | public TestShellTab(Context context, String url, WindowAndroid window) { |
| 41 | super(window); |
| 42 | init(context); |
| 43 | loadUrlWithSanitization(url); |
| 44 | } |
| 45 | |
| 46 | /** |
| 47 | * @param context The Context the view is running in. |
| 48 | */ |
| 49 | private void init(Context context) { |
| 50 | // Build the WebContents and the ContentView/ContentViewCore |
| 51 | int nativeWebContentsPtr = ContentViewUtil.createNativeWebContents(false); |
| 52 | mContentView = ContentView.newInstance(context, nativeWebContentsPtr, getWindowAndroid()); |
| 53 | mNativeTestShellTab = nativeInit(nativeWebContentsPtr, |
| 54 | getWindowAndroid().getNativePointer()); |
| 55 | |
| 56 | // Build the WebContentsDelegate |
| 57 | mWebContentsDelegate = new TabBaseChromeWebContentsDelegateAndroid(); |
| 58 | nativeInitWebContentsDelegate(mNativeTestShellTab, mWebContentsDelegate); |
| 59 | |
| 60 | // To be called after everything is initialized. |
| 61 | mCleanupReference = new CleanupReference(this, |
| 62 | new DestroyRunnable(mNativeTestShellTab)); |
| 63 | } |
| 64 | |
| 65 | /** |
| 66 | * Should be called when the tab is no longer needed. Once this is called this tab should not |
| 67 | * be used. |
| 68 | */ |
| 69 | public void destroy() { |
| 70 | for (TestShellTabObserver observer : mObservers) { |
| 71 | observer.onCloseTab(TestShellTab.this); |
| 72 | } |
| 73 | destroyContentView(); |
| 74 | if (mNativeTestShellTab != 0) { |
| 75 | mCleanupReference.cleanupNow(); |
| 76 | mNativeTestShellTab = 0; |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | /** |
| 81 | * @param observer The {@link TestShellTabObserver} that should be notified of changes. |
| 82 | */ |
| 83 | public void addObserver(TestShellTabObserver observer) { |
| 84 | mObservers.addObserver(observer); |
| 85 | } |
| 86 | |
| 87 | /** |
| 88 | * @param observer The {@link TestShellTabObserver} that should no longer be notified of |
| 89 | * changes. |
| 90 | */ |
| 91 | public void removeObserver(TestShellTabObserver observer) { |
| 92 | mObservers.removeObserver(observer); |
| 93 | } |
| 94 | |
| 95 | /** |
| 96 | * @return Whether or not the tab is currently loading. |
| 97 | */ |
| 98 | public boolean isLoading() { |
| 99 | return mIsLoading; |
| 100 | } |
| 101 | |
| 102 | /** |
| 103 | * @return The {@link ContentView} represented by this tab. |
| 104 | */ |
| 105 | public ContentView getContentView() { |
| 106 | return mContentView; |
| 107 | } |
| 108 | |
| 109 | |
| 110 | private void destroyContentView() { |
| 111 | if (mContentView == null) return; |
| 112 | |
| 113 | mContentView.destroy(); |
| 114 | mContentView = null; |
| 115 | } |
| 116 | |
| 117 | /** |
| 118 | * Navigates this Tab's {@link ContentView} to a sanitized version of {@code url}. |
| 119 | * @param url The potentially unsanitized URL to navigate to. |
| 120 | */ |
| 121 | public void loadUrlWithSanitization(String url) { |
| 122 | if (url == null) return; |
| 123 | |
| 124 | // Sanitize the URL. |
| 125 | url = nativeFixupUrl(mNativeTestShellTab, url); |
| 126 | |
| 127 | // Invalid URLs will just return empty. |
| 128 | if (TextUtils.isEmpty(url)) return; |
| 129 | |
| 130 | if (TextUtils.equals(url, mContentView.getUrl())) { |
| 131 | mContentView.reload(); |
| 132 | } else { |
| 133 | mContentView.loadUrl(new LoadUrlParams(url)); |
| 134 | } |
| 135 | } |
| 136 | |
| 137 | private static final class DestroyRunnable implements Runnable { |
| 138 | private final int mNativeTestShellTab; |
| 139 | private DestroyRunnable(int nativeTestShellTab) { |
| 140 | mNativeTestShellTab = nativeTestShellTab; |
| 141 | } |
| 142 | @Override |
| 143 | public void run() { |
| 144 | nativeDestroy(mNativeTestShellTab); |
| 145 | } |
| 146 | } |
| 147 | |
| 148 | private class TabBaseChromeWebContentsDelegateAndroid |
| 149 | extends ChromeWebContentsDelegateAndroid { |
| 150 | @Override |
| 151 | public void onLoadProgressChanged(int progress) { |
| 152 | for (TestShellTabObserver observer : mObservers) { |
| 153 | observer.onLoadProgressChanged(TestShellTab.this, progress); |
| 154 | } |
| 155 | } |
| 156 | |
| 157 | @Override |
| 158 | public void onUpdateUrl(String url) { |
| 159 | for (TestShellTabObserver observer : mObservers) { |
| 160 | observer.onUpdateUrl(TestShellTab.this, url); |
| 161 | } |
| 162 | } |
| 163 | |
| 164 | @Override |
| 165 | public void onLoadStarted() { |
| 166 | mIsLoading = true; |
| 167 | } |
| 168 | |
| 169 | @Override |
| 170 | public void onLoadStopped() { |
| 171 | mIsLoading = false; |
| 172 | } |
| 173 | } |
| 174 | |
| 175 | private native int nativeInit(int webContentsPtr, int windowAndroidPtr); |
| 176 | private static native void nativeDestroy(int nativeTestShellTab); |
| 177 | private native void nativeInitWebContentsDelegate(int nativeTestShellTab, |
| 178 | ChromeWebContentsDelegateAndroid chromeWebContentsDelegateAndroid); |
| 179 | private native String nativeFixupUrl(int nativeTestShellTab, String url); |
| 180 | } |