1 // Copyright 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.
5 package org.chromium.chrome.testshell;
7 import android.app.Activity;
8 import android.content.Intent;
9 import android.content.res.TypedArray;
10 import android.os.Bundle;
11 import android.text.TextUtils;
12 import android.util.Log;
13 import android.view.KeyEvent;
14 import android.view.Menu;
15 import android.view.MenuItem;
16 import android.widget.Toast;
18 import com.google.common.annotations.VisibleForTesting;
20 import org.chromium.base.ApiCompatibilityUtils;
21 import org.chromium.base.BaseSwitches;
22 import org.chromium.base.CommandLine;
23 import org.chromium.base.MemoryPressureListener;
24 import org.chromium.base.library_loader.ProcessInitException;
25 import org.chromium.chrome.browser.DevToolsServer;
26 import org.chromium.chrome.browser.appmenu.AppMenuHandler;
27 import org.chromium.chrome.browser.appmenu.AppMenuPropertiesDelegate;
28 import org.chromium.chrome.browser.printing.PrintingControllerFactory;
29 import org.chromium.chrome.browser.printing.TabPrinter;
30 import org.chromium.chrome.testshell.sync.SyncController;
31 import org.chromium.content.browser.ActivityContentVideoViewClient;
32 import org.chromium.content.browser.BrowserStartupController;
33 import org.chromium.content.browser.ContentView;
34 import org.chromium.content.browser.DeviceUtils;
35 import org.chromium.printing.PrintingController;
36 import org.chromium.sync.signin.ChromeSigninController;
37 import org.chromium.ui.base.ActivityWindowAndroid;
38 import org.chromium.ui.base.WindowAndroid;
41 * The {@link android.app.Activity} component of a basic test shell to test Chrome features.
43 public class ChromiumTestShellActivity extends Activity implements AppMenuPropertiesDelegate {
44 private static final String TAG = "ChromiumTestShellActivity";
46 private WindowAndroid mWindow;
47 private TabManager mTabManager;
48 private DevToolsServer mDevToolsServer;
49 private SyncController mSyncController;
50 private PrintingController mPrintingController;
52 private AppMenuHandler mAppMenuHandler;
55 protected void onCreate(final Bundle savedInstanceState) {
56 super.onCreate(savedInstanceState);
58 ChromiumTestShellApplication.initCommandLine();
59 waitForDebuggerIfNeeded();
61 DeviceUtils.addDeviceSpecificUserAgentSwitch(this);
63 BrowserStartupController.StartupCallback callback =
64 new BrowserStartupController.StartupCallback() {
66 public void onSuccess(boolean alreadyStarted) {
67 finishInitialization(savedInstanceState);
71 public void onFailure() {
72 Toast.makeText(ChromiumTestShellActivity.this,
73 R.string.browser_process_initialization_failed,
74 Toast.LENGTH_SHORT).show();
75 Log.e(TAG, "Chromium browser process initialization failed");
80 BrowserStartupController.get(this).startBrowserProcessesAsync(callback);
82 catch (ProcessInitException e) {
83 Log.e(TAG, "Unable to load native library.", e);
88 private void finishInitialization(final Bundle savedInstanceState) {
89 setContentView(R.layout.testshell_activity);
90 mTabManager = (TabManager) findViewById(R.id.tab_manager);
92 mWindow = new ActivityWindowAndroid(this);
93 mWindow.restoreInstanceState(savedInstanceState);
94 mTabManager.initialize(mWindow, new ActivityContentVideoViewClient(this));
96 String startupUrl = getUrlFromIntent(getIntent());
97 if (!TextUtils.isEmpty(startupUrl)) {
98 mTabManager.setStartupUrl(startupUrl);
100 TestShellToolbar mToolbar = (TestShellToolbar) findViewById(R.id.toolbar);
101 mAppMenuHandler = new AppMenuHandler(this, this, R.menu.main_menu);
102 mToolbar.setMenuHandler(mAppMenuHandler);
104 mDevToolsServer = new DevToolsServer("chromium_testshell");
105 mDevToolsServer.setRemoteDebuggingEnabled(true);
107 mPrintingController = PrintingControllerFactory.create(this);
109 mSyncController = SyncController.get(this);
110 // In case this method is called after the first onStart(), we need to inform the
111 // SyncController that we have started.
112 mSyncController.onStart();
116 protected void onDestroy() {
119 if (mDevToolsServer != null) mDevToolsServer.destroy();
120 mDevToolsServer = null;
124 protected void onSaveInstanceState(Bundle outState) {
125 // TODO(dtrainor): Save/restore the tab state.
126 if (mWindow != null) mWindow.saveInstanceState(outState);
130 public boolean onKeyUp(int keyCode, KeyEvent event) {
131 if (keyCode == KeyEvent.KEYCODE_BACK) {
132 TestShellTab tab = getActiveTab();
133 if (tab != null && tab.getContentView().canGoBack()) {
134 tab.getContentView().goBack();
139 return super.onKeyUp(keyCode, event);
143 protected void onNewIntent(Intent intent) {
144 if (MemoryPressureListener.handleDebugIntent(this, intent.getAction())) return;
146 String url = getUrlFromIntent(intent);
147 if (!TextUtils.isEmpty(url)) {
148 TestShellTab tab = getActiveTab();
149 if (tab != null) tab.loadUrlWithSanitization(url);
154 protected void onStop() {
157 ContentView view = getActiveContentView();
158 if (view != null) view.onHide();
162 protected void onStart() {
165 ContentView view = getActiveContentView();
166 if (view != null) view.onShow();
168 if (mSyncController != null) {
169 mSyncController.onStart();
174 public void onActivityResult(int requestCode, int resultCode, Intent data) {
175 mWindow.onActivityResult(requestCode, resultCode, data);
179 * @return The {@link WindowAndroid} associated with this activity.
181 public WindowAndroid getWindowAndroid() {
186 * @return The {@link TestShellTab} that is currently visible.
188 public TestShellTab getActiveTab() {
189 return mTabManager != null ? mTabManager.getCurrentTab() : null;
193 * @return The ContentView of the active tab.
195 public ContentView getActiveContentView() {
196 TestShellTab tab = getActiveTab();
197 return tab != null ? tab.getContentView() : null;
201 * Creates a {@link TestShellTab} with a URL specified by {@code url}.
203 * @param url The URL the new {@link TestShellTab} should start with.
206 public void createTab(String url) {
207 mTabManager.createTab(url);
211 * Override the menu key event to show AppMenu.
214 public boolean onKeyDown(int keyCode, KeyEvent event) {
215 if (keyCode == KeyEvent.KEYCODE_MENU && event.getRepeatCount() == 0) {
216 mAppMenuHandler.showAppMenu(findViewById(R.id.menu_button), true, false);
219 return super.onKeyDown(keyCode, event);
223 public boolean onOptionsItemSelected(MenuItem item) {
224 switch (item.getItemId()) {
226 if (ChromeSigninController.get(this).isSignedIn())
227 SyncController.openSignOutDialog(getFragmentManager());
229 SyncController.openSigninDialog(getFragmentManager());
232 if (getActiveTab() != null) {
233 mPrintingController.startPrint(new TabPrinter(getActiveTab()));
236 case R.id.back_menu_id:
237 if (getActiveTab().canGoBack()) getActiveTab().goBack();
239 case R.id.forward_menu_id:
240 if (getActiveTab().canGoForward()) getActiveTab().goForward();
243 return super.onOptionsItemSelected(item);
247 private void waitForDebuggerIfNeeded() {
248 if (CommandLine.getInstance().hasSwitch(BaseSwitches.WAIT_FOR_JAVA_DEBUGGER)) {
249 Log.e(TAG, "Waiting for Java debugger to connect...");
250 android.os.Debug.waitForDebugger();
251 Log.e(TAG, "Java debugger connected. Resuming execution.");
255 private static String getUrlFromIntent(Intent intent) {
256 return intent != null ? intent.getDataString() : null;
260 public boolean shouldShowAppMenu() {
265 public void prepareMenu(Menu menu) {
266 // Disable the "Back" menu item if there is no page to go to.
267 MenuItem backMenuItem = menu.findItem(R.id.back_menu_id);
268 backMenuItem.setEnabled(getActiveTab().canGoBack());
270 // Disable the "Forward" menu item if there is no page to go to.
271 MenuItem forwardMenuItem = menu.findItem(R.id.forward_menu_id);
272 forwardMenuItem.setEnabled(getActiveTab().canGoForward());
274 // ChromiumTestShell does not know about bookmarks yet
275 menu.findItem(R.id.bookmark_this_page_id).setEnabled(false);
277 MenuItem signinItem = menu.findItem(R.id.signin);
278 if (ChromeSigninController.get(this).isSignedIn()) {
279 signinItem.setTitle(ChromeSigninController.get(this).getSignedInAccountName());
281 signinItem.setTitle(R.string.signin_sign_in);
284 menu.findItem(R.id.print).setVisible(ApiCompatibilityUtils.isPrintingSupported());
286 menu.setGroupVisible(R.id.MAIN_MENU, true);
290 public boolean shouldShowIconRow() {
295 public int getMenuThemeResourceId() {
296 return android.R.style.Theme_Holo_Light;
300 public int getItemRowHeight() {
301 TypedArray a = obtainStyledAttributes(
302 new int[] {android.R.attr.listPreferredItemHeightSmall});
303 int itemRowHeight = a.getDimensionPixelSize(0, 0);
305 return itemRowHeight;