ContentShellActivity.java revision d0247b1b59f9c528cb6df88b4f2b9afaf80d181e
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 5package org.chromium.content_shell_apk; 6 7import android.app.Activity; 8import android.content.BroadcastReceiver; 9import android.content.Context; 10import android.content.Intent; 11import android.content.IntentFilter; 12import android.os.Bundle; 13import android.text.TextUtils; 14import android.util.Log; 15import android.view.KeyEvent; 16import android.widget.Toast; 17 18import org.chromium.base.MemoryPressureListener; 19import org.chromium.content.app.LibraryLoader; 20import org.chromium.content.browser.ActivityContentVideoViewClient; 21import org.chromium.content.browser.BrowserStartupController; 22import org.chromium.content.browser.ContentVideoViewClient; 23import org.chromium.content.browser.ContentView; 24import org.chromium.content.browser.ContentViewClient; 25import org.chromium.content.browser.DeviceUtils; 26import org.chromium.content.browser.TracingIntentHandler; 27import org.chromium.content.common.CommandLine; 28import org.chromium.content.common.ProcessInitException; 29import org.chromium.content_shell.Shell; 30import org.chromium.content_shell.ShellManager; 31import org.chromium.ui.WindowAndroid; 32 33/** 34 * Activity for managing the Content Shell. 35 */ 36public class ContentShellActivity extends Activity { 37 38 public static final String COMMAND_LINE_FILE = "/data/local/tmp/content-shell-command-line"; 39 private static final String TAG = "ContentShellActivity"; 40 41 private static final String ACTIVE_SHELL_URL_KEY = "activeUrl"; 42 private static final String ACTION_START_TRACE = 43 "org.chromium.content_shell.action.PROFILE_START"; 44 private static final String ACTION_STOP_TRACE = 45 "org.chromium.content_shell.action.PROFILE_STOP"; 46 public static final String COMMAND_LINE_ARGS_KEY = "commandLineArgs"; 47 48 /** 49 * Sending an intent with this action will simulate a memory pressure signal at a critical 50 * level. 51 */ 52 private static final String ACTION_LOW_MEMORY = 53 "org.chromium.content_shell.action.ACTION_LOW_MEMORY"; 54 55 /** 56 * Sending an intent with this action will simulate a memory pressure signal at a moderate 57 * level. 58 */ 59 private static final String ACTION_TRIM_MEMORY_MODERATE = 60 "org.chromium.content_shell.action.ACTION_TRIM_MEMORY_MODERATE"; 61 62 63 private ShellManager mShellManager; 64 private WindowAndroid mWindowAndroid; 65 private BroadcastReceiver mReceiver; 66 67 @Override 68 protected void onCreate(final Bundle savedInstanceState) { 69 super.onCreate(savedInstanceState); 70 71 // Initializing the command line must occur before loading the library. 72 if (!CommandLine.isInitialized()) { 73 CommandLine.initFromFile(COMMAND_LINE_FILE); 74 String[] commandLineParams = getCommandLineParamsFromIntent(getIntent()); 75 if (commandLineParams != null) { 76 CommandLine.getInstance().appendSwitchesAndArguments(commandLineParams); 77 } 78 } 79 waitForDebuggerIfNeeded(); 80 81 DeviceUtils.addDeviceSpecificUserAgentSwitch(this); 82 try { 83 LibraryLoader.ensureInitialized(); 84 } catch (ProcessInitException e) { 85 Log.e(TAG, "ContentView initialization failed.", e); 86 finish(); 87 return; 88 } 89 90 setContentView(R.layout.content_shell_activity); 91 mShellManager = (ShellManager) findViewById(R.id.shell_container); 92 mWindowAndroid = new WindowAndroid(this); 93 mWindowAndroid.restoreInstanceState(savedInstanceState); 94 mShellManager.setWindow(mWindowAndroid); 95 96 String startupUrl = getUrlFromIntent(getIntent()); 97 if (!TextUtils.isEmpty(startupUrl)) { 98 mShellManager.setStartupUrl(Shell.sanitizeUrl(startupUrl)); 99 } 100 101 if (CommandLine.getInstance().hasSwitch(CommandLine.DUMP_RENDER_TREE)) { 102 if(BrowserStartupController.get(this).startBrowserProcessesSync( 103 BrowserStartupController.MAX_RENDERERS_LIMIT)) { 104 finishInitialization(savedInstanceState); 105 } else { 106 initializationFailed(); 107 } 108 } else { 109 BrowserStartupController.get(this).startBrowserProcessesAsync( 110 new BrowserStartupController.StartupCallback() { 111 @Override 112 public void onSuccess(boolean alreadyStarted) { 113 finishInitialization(savedInstanceState); 114 } 115 116 @Override 117 public void onFailure() { 118 initializationFailed(); 119 } 120 }); 121 } 122 } 123 124 private void finishInitialization(Bundle savedInstanceState) { 125 String shellUrl = ShellManager.DEFAULT_SHELL_URL; 126 if (savedInstanceState != null 127 && savedInstanceState.containsKey(ACTIVE_SHELL_URL_KEY)) { 128 shellUrl = savedInstanceState.getString(ACTIVE_SHELL_URL_KEY); 129 } 130 mShellManager.launchShell(shellUrl); 131 getActiveContentView().setContentViewClient(new ContentViewClient() { 132 @Override 133 public ContentVideoViewClient getContentVideoViewClient() { 134 return new ActivityContentVideoViewClient(ContentShellActivity.this); 135 } 136 }); 137 } 138 139 private void initializationFailed() { 140 Log.e(TAG, "ContentView initialization failed."); 141 Toast.makeText(ContentShellActivity.this, 142 R.string.browser_process_initialization_failed, 143 Toast.LENGTH_SHORT).show(); 144 finish(); 145 } 146 147 @Override 148 protected void onSaveInstanceState(Bundle outState) { 149 super.onSaveInstanceState(outState); 150 Shell activeShell = getActiveShell(); 151 if (activeShell != null) { 152 outState.putString(ACTIVE_SHELL_URL_KEY, activeShell.getContentView().getUrl()); 153 } 154 155 mWindowAndroid.saveInstanceState(outState); 156 } 157 158 private void waitForDebuggerIfNeeded() { 159 if (CommandLine.getInstance().hasSwitch(CommandLine.WAIT_FOR_JAVA_DEBUGGER)) { 160 Log.e(TAG, "Waiting for Java debugger to connect..."); 161 android.os.Debug.waitForDebugger(); 162 Log.e(TAG, "Java debugger connected. Resuming execution."); 163 } 164 } 165 166 @Override 167 public boolean onKeyUp(int keyCode, KeyEvent event) { 168 if (keyCode != KeyEvent.KEYCODE_BACK) return super.onKeyUp(keyCode, event); 169 170 Shell activeView = getActiveShell(); 171 if (activeView != null && activeView.getContentView().canGoBack()) { 172 activeView.getContentView().goBack(); 173 return true; 174 } 175 176 return super.onKeyUp(keyCode, event); 177 } 178 179 @Override 180 protected void onNewIntent(Intent intent) { 181 if (getCommandLineParamsFromIntent(intent) != null) { 182 Log.i(TAG, "Ignoring command line params: can only be set when creating the activity."); 183 } 184 185 if (ACTION_LOW_MEMORY.equals(intent.getAction())) { 186 MemoryPressureListener.simulateMemoryPressureSignal(TRIM_MEMORY_COMPLETE); 187 return; 188 } else if (ACTION_TRIM_MEMORY_MODERATE.equals(intent.getAction())) { 189 MemoryPressureListener.simulateMemoryPressureSignal(TRIM_MEMORY_MODERATE); 190 return; 191 } 192 193 String url = getUrlFromIntent(intent); 194 if (!TextUtils.isEmpty(url)) { 195 Shell activeView = getActiveShell(); 196 if (activeView != null) { 197 activeView.loadUrl(url); 198 } 199 } 200 } 201 202 @Override 203 protected void onPause() { 204 ContentView view = getActiveContentView(); 205 if (view != null) view.onActivityPause(); 206 207 super.onPause(); 208 unregisterReceiver(mReceiver); 209 } 210 211 @Override 212 protected void onResume() { 213 super.onResume(); 214 215 ContentView view = getActiveContentView(); 216 if (view != null) view.onActivityResume(); 217 IntentFilter intentFilter = new IntentFilter(ACTION_START_TRACE); 218 intentFilter.addAction(ACTION_STOP_TRACE); 219 mReceiver = new BroadcastReceiver() { 220 @Override 221 public void onReceive(Context context, Intent intent) { 222 String action = intent.getAction(); 223 String extra = intent.getStringExtra("file"); 224 if (ACTION_START_TRACE.equals(action)) { 225 if (extra.isEmpty()) { 226 Log.e(TAG, "Can not start tracing without specifing saving location"); 227 } else { 228 TracingIntentHandler.beginTracing(extra); 229 Log.i(TAG, "start tracing"); 230 } 231 } else if (ACTION_STOP_TRACE.equals(action)) { 232 Log.i(TAG, "stop tracing"); 233 TracingIntentHandler.endTracing(); 234 } 235 } 236 }; 237 registerReceiver(mReceiver, intentFilter); 238 } 239 240 @Override 241 public void onActivityResult(int requestCode, int resultCode, Intent data) { 242 super.onActivityResult(requestCode, resultCode, data); 243 mWindowAndroid.onActivityResult(requestCode, resultCode, data); 244 } 245 246 private static String getUrlFromIntent(Intent intent) { 247 return intent != null ? intent.getDataString() : null; 248 } 249 250 private static String[] getCommandLineParamsFromIntent(Intent intent) { 251 return intent != null ? intent.getStringArrayExtra(COMMAND_LINE_ARGS_KEY) : null; 252 } 253 254 /** 255 * @return The {@link ShellManager} configured for the activity or null if it has not been 256 * created yet. 257 */ 258 public ShellManager getShellManager() { 259 return mShellManager; 260 } 261 262 /** 263 * @return The currently visible {@link Shell} or null if one is not showing. 264 */ 265 public Shell getActiveShell() { 266 return mShellManager != null ? mShellManager.getActiveShell() : null; 267 } 268 269 /** 270 * @return The {@link ContentView} owned by the currently visible {@link Shell} or null if one 271 * is not showing. 272 */ 273 public ContentView getActiveContentView() { 274 Shell shell = getActiveShell(); 275 return shell != null ? shell.getContentView() : null; 276 } 277} 278