Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / android / shell / java / src / org / chromium / chrome / shell / ChromeShellActivity.java
1 // Copyright 2014 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.shell;
6
7 import android.app.Activity;
8 import android.content.Intent;
9 import android.os.Bundle;
10 import android.text.TextUtils;
11 import android.util.Log;
12 import android.view.KeyEvent;
13 import android.view.Menu;
14 import android.view.MenuItem;
15 import android.view.View;
16 import android.widget.Toast;
17
18 import com.google.common.annotations.VisibleForTesting;
19
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.browser.share.ShareHelper;
31 import org.chromium.chrome.shell.sync.SyncController;
32 import org.chromium.components.dom_distiller.core.DomDistillerUrlUtils;
33 import org.chromium.content.browser.ActivityContentVideoViewClient;
34 import org.chromium.content.browser.BrowserStartupController;
35 import org.chromium.content.browser.ContentViewCore;
36 import org.chromium.content.browser.DeviceUtils;
37 import org.chromium.content.common.ContentSwitches;
38 import org.chromium.printing.PrintManagerDelegateImpl;
39 import org.chromium.printing.PrintingController;
40 import org.chromium.sync.signin.AccountManagerHelper;
41 import org.chromium.sync.signin.ChromeSigninController;
42 import org.chromium.ui.base.ActivityWindowAndroid;
43 import org.chromium.ui.base.WindowAndroid;
44
45 /**
46  * The {@link android.app.Activity} component of a basic test shell to test Chrome features.
47  */
48 public class ChromeShellActivity extends Activity implements AppMenuPropertiesDelegate {
49     private static final String TAG = "ChromeShellActivity";
50     private static final String CHROME_DISTILLER_SCHEME = "chrome-distiller";
51
52     /**
53      * Factory used to set up a mock ActivityWindowAndroid for testing.
54      */
55     public interface ActivityWindowAndroidFactory {
56         /**
57          * @return ActivityWindowAndroid for the given activity.
58          */
59         public ActivityWindowAndroid getActivityWindowAndroid(Activity activity);
60     }
61
62     private static ActivityWindowAndroidFactory sWindowAndroidFactory =
63             new ActivityWindowAndroidFactory() {
64                 @Override
65                 public ActivityWindowAndroid getActivityWindowAndroid(Activity activity) {
66                     return new ActivityWindowAndroid(activity);
67                 }
68             };
69
70     private WindowAndroid mWindow;
71     private TabManager mTabManager;
72     private DevToolsServer mDevToolsServer;
73     private SyncController mSyncController;
74     private PrintingController mPrintingController;
75
76     /**
77      * Factory used to set up a mock AppMenuHandler for testing.
78      */
79     public interface AppMenuHandlerFactory {
80         /**
81          * @return AppMenuHandler for the given activity and menu resource id.
82          */
83         public AppMenuHandler getAppMenuHandler(Activity activity,
84                 AppMenuPropertiesDelegate delegate, int menuResourceId);
85     }
86
87     private static AppMenuHandlerFactory sAppMenuHandlerFactory =
88             new AppMenuHandlerFactory() {
89                 @Override
90                 public AppMenuHandler getAppMenuHandler(Activity activity,
91                         AppMenuPropertiesDelegate delegate, int menuResourceId) {
92                     return new AppMenuHandler(activity, delegate, menuResourceId);
93                 }
94             };
95     private AppMenuHandler mAppMenuHandler;
96
97     @Override
98     protected void onCreate(final Bundle savedInstanceState) {
99         super.onCreate(savedInstanceState);
100
101         ChromeShellApplication.initCommandLine();
102         waitForDebuggerIfNeeded();
103
104         DeviceUtils.addDeviceSpecificUserAgentSwitch(this);
105
106         BrowserStartupController.StartupCallback callback =
107                 new BrowserStartupController.StartupCallback() {
108                     @Override
109                     public void onSuccess(boolean alreadyStarted) {
110                         finishInitialization(savedInstanceState);
111                     }
112
113                     @Override
114                     public void onFailure() {
115                         Toast.makeText(ChromeShellActivity.this,
116                                        R.string.browser_process_initialization_failed,
117                                        Toast.LENGTH_SHORT).show();
118                         Log.e(TAG, "Chromium browser process initialization failed");
119                         finish();
120                     }
121                 };
122         try {
123             BrowserStartupController.get(this).startBrowserProcessesAsync(callback);
124         } catch (ProcessInitException e) {
125             Log.e(TAG, "Unable to load native library.", e);
126             System.exit(-1);
127         }
128     }
129
130     private void finishInitialization(final Bundle savedInstanceState) {
131         setContentView(R.layout.chrome_shell_activity);
132         mTabManager = (TabManager) findViewById(R.id.tab_manager);
133
134         mWindow = sWindowAndroidFactory.getActivityWindowAndroid(this);
135         mWindow.restoreInstanceState(savedInstanceState);
136         mTabManager.initialize(mWindow, new ActivityContentVideoViewClient(this) {
137             @Override
138             public boolean onShowCustomView(View view) {
139                 if (mTabManager == null) return false;
140                 boolean success = super.onShowCustomView(view);
141                 if (!CommandLine.getInstance().hasSwitch(
142                         ContentSwitches.DISABLE_OVERLAY_FULLSCREEN_VIDEO_SUBTITLE)) {
143                     mTabManager.setOverlayVideoMode(true);
144                 }
145                 return success;
146             }
147
148             @Override
149             public void onDestroyContentVideoView() {
150                 super.onDestroyContentVideoView();
151                 if (mTabManager != null && !CommandLine.getInstance().hasSwitch(
152                         ContentSwitches.DISABLE_OVERLAY_FULLSCREEN_VIDEO_SUBTITLE)) {
153                     mTabManager.setOverlayVideoMode(false);
154                 }
155             }
156         });
157
158         String startupUrl = getUrlFromIntent(getIntent());
159         if (!TextUtils.isEmpty(startupUrl)) {
160             mTabManager.setStartupUrl(startupUrl);
161         }
162         ChromeShellToolbar mToolbar = (ChromeShellToolbar) findViewById(R.id.toolbar);
163         mAppMenuHandler = sAppMenuHandlerFactory.getAppMenuHandler(this, this, R.menu.main_menu);
164         mToolbar.setMenuHandler(mAppMenuHandler);
165
166         mDevToolsServer = new DevToolsServer("chrome_shell");
167         mDevToolsServer.setRemoteDebuggingEnabled(true);
168
169         mPrintingController = PrintingControllerFactory.create(this);
170
171         mSyncController = SyncController.get(this);
172         // In case this method is called after the first onStart(), we need to inform the
173         // SyncController that we have started.
174         mSyncController.onStart();
175     }
176
177     @Override
178     protected void onDestroy() {
179         super.onDestroy();
180
181         if (mDevToolsServer != null) mDevToolsServer.destroy();
182         mDevToolsServer = null;
183     }
184
185     @Override
186     protected void onSaveInstanceState(Bundle outState) {
187         // TODO(dtrainor): Save/restore the tab state.
188         if (mWindow != null) mWindow.saveInstanceState(outState);
189     }
190
191     @Override
192     public boolean onKeyUp(int keyCode, KeyEvent event) {
193         if (keyCode == KeyEvent.KEYCODE_BACK) {
194             ChromeShellTab tab = getActiveTab();
195             if (tab != null && tab.canGoBack()) {
196                 tab.goBack();
197                 return true;
198             }
199         }
200
201         return super.onKeyUp(keyCode, event);
202     }
203
204     @Override
205     protected void onNewIntent(Intent intent) {
206         if (MemoryPressureListener.handleDebugIntent(this, intent.getAction())) return;
207
208         String url = getUrlFromIntent(intent);
209         if (!TextUtils.isEmpty(url)) {
210             ChromeShellTab tab = getActiveTab();
211             if (tab != null) tab.loadUrlWithSanitization(url);
212         }
213     }
214
215     @Override
216     protected void onStop() {
217         super.onStop();
218
219         ContentViewCore viewCore = getActiveContentViewCore();
220         if (viewCore != null) viewCore.onHide();
221     }
222
223     @Override
224     protected void onStart() {
225         super.onStart();
226
227         ContentViewCore viewCore = getActiveContentViewCore();
228         if (viewCore != null) viewCore.onShow();
229
230         if (mSyncController != null) {
231             mSyncController.onStart();
232         }
233     }
234
235     @Override
236     public void onActivityResult(int requestCode, int resultCode, Intent data) {
237         mWindow.onActivityResult(requestCode, resultCode, data);
238     }
239
240     /**
241      * @return The {@link WindowAndroid} associated with this activity.
242      */
243     public WindowAndroid getWindowAndroid() {
244         return mWindow;
245     }
246
247     /**
248      * @return The {@link ChromeShellTab} that is currently visible.
249      */
250     public ChromeShellTab getActiveTab() {
251         return mTabManager != null ? mTabManager.getCurrentTab() : null;
252     }
253
254     /**
255      * @return The ContentViewCore of the active tab.
256      */
257     public ContentViewCore getActiveContentViewCore() {
258         ChromeShellTab tab = getActiveTab();
259         return tab != null ? tab.getContentViewCore() : null;
260     }
261
262     /**
263      * Creates a {@link ChromeShellTab} with a URL specified by {@code url}.
264      *
265      * @param url The URL the new {@link ChromeShellTab} should start with.
266      */
267     @VisibleForTesting
268     public void createTab(String url) {
269         mTabManager.createTab(url);
270     }
271
272     /**
273      * Override the menu key event to show AppMenu.
274      */
275     @Override
276     public boolean onKeyDown(int keyCode, KeyEvent event) {
277         if (keyCode == KeyEvent.KEYCODE_MENU && event.getRepeatCount() == 0) {
278             mAppMenuHandler.showAppMenu(findViewById(R.id.menu_button), true, false);
279             return true;
280         }
281         return super.onKeyDown(keyCode, event);
282     }
283
284     @Override
285     public boolean onOptionsItemSelected(MenuItem item) {
286         ChromeShellTab activeTab = getActiveTab();
287         switch (item.getItemId()) {
288             case R.id.signin:
289                 if (ChromeSigninController.get(this).isSignedIn()) {
290                     SyncController.openSignOutDialog(getFragmentManager());
291                 } else if (AccountManagerHelper.get(this).hasGoogleAccounts()) {
292                     SyncController.openSigninDialog(getFragmentManager());
293                 } else {
294                     Toast.makeText(this, R.string.signin_no_account, Toast.LENGTH_SHORT).show();
295                 }
296                 return true;
297             case R.id.print:
298                 if (activeTab != null) {
299                     mPrintingController.startPrint(new TabPrinter(activeTab),
300                             new PrintManagerDelegateImpl(this));
301                 }
302                 return true;
303             case R.id.distill_page:
304                 if (activeTab != null) {
305                     String viewUrl = DomDistillerUrlUtils.getDistillerViewUrlFromUrl(
306                             CHROME_DISTILLER_SCHEME, activeTab.getUrl());
307                     activeTab.loadUrlWithSanitization(viewUrl);
308                 }
309                 return true;
310             case R.id.back_menu_id:
311                 if (activeTab != null && activeTab.canGoBack()) {
312                     activeTab.goBack();
313                 }
314                 return true;
315             case R.id.forward_menu_id:
316                 if (activeTab != null && activeTab.canGoForward()) {
317                     activeTab.goForward();
318                 }
319                 return true;
320             case R.id.share_menu_id:
321             case R.id.direct_share_menu_id:
322                 ShareHelper.share(item.getItemId() == R.id.direct_share_menu_id, this,
323                         activeTab.getTitle(), activeTab.getUrl(), null);
324                 return true;
325             default:
326                 return super.onOptionsItemSelected(item);
327         }
328     }
329
330     private void waitForDebuggerIfNeeded() {
331         if (CommandLine.getInstance().hasSwitch(BaseSwitches.WAIT_FOR_JAVA_DEBUGGER)) {
332             Log.e(TAG, "Waiting for Java debugger to connect...");
333             android.os.Debug.waitForDebugger();
334             Log.e(TAG, "Java debugger connected. Resuming execution.");
335         }
336     }
337
338     private static String getUrlFromIntent(Intent intent) {
339         return intent != null ? intent.getDataString() : null;
340     }
341
342     @Override
343     public boolean shouldShowAppMenu() {
344         return true;
345     }
346
347     @Override
348     public void prepareMenu(Menu menu) {
349         menu.setGroupVisible(R.id.MAIN_MENU, true);
350         ChromeShellTab activeTab = getActiveTab();
351
352         // Disable the "Back" menu item if there is no page to go to.
353         MenuItem backMenuItem = menu.findItem(R.id.back_menu_id);
354         backMenuItem.setEnabled(activeTab != null ? activeTab.canGoBack() : false);
355
356         // Disable the "Forward" menu item if there is no page to go to.
357         MenuItem forwardMenuItem = menu.findItem(R.id.forward_menu_id);
358         forwardMenuItem.setEnabled(activeTab != null ? activeTab.canGoForward() : false);
359
360         // ChromeShell does not know about bookmarks yet
361         menu.findItem(R.id.bookmark_this_page_id).setEnabled(true);
362
363         MenuItem signinItem = menu.findItem(R.id.signin);
364         if (ChromeSigninController.get(this).isSignedIn()) {
365             signinItem.setTitle(ChromeSigninController.get(this).getSignedInAccountName());
366         } else {
367             signinItem.setTitle(R.string.signin_sign_in);
368         }
369
370         menu.findItem(R.id.print).setVisible(ApiCompatibilityUtils.isPrintingSupported());
371
372         MenuItem distillPageItem = menu.findItem(R.id.distill_page);
373         if (CommandLine.getInstance().hasSwitch(ChromeShellSwitches.ENABLE_DOM_DISTILLER)) {
374             String url = activeTab != null ? activeTab.getUrl() : null;
375             distillPageItem.setEnabled(!DomDistillerUrlUtils.isUrlReportable(
376                     CHROME_DISTILLER_SCHEME, url));
377             distillPageItem.setVisible(true);
378         } else {
379             distillPageItem.setVisible(false);
380         }
381         ShareHelper.configureDirectShareMenuItem(this, menu.findItem(R.id.direct_share_menu_id));
382     }
383
384     @VisibleForTesting
385     public AppMenuHandler getAppMenuHandler() {
386         return mAppMenuHandler;
387     }
388
389     @Override
390     public int getMenuThemeResourceId() {
391         return android.R.style.Theme_Holo_Light;
392     }
393
394     @VisibleForTesting
395     public static void setActivityWindowAndroidFactory(ActivityWindowAndroidFactory factory) {
396         sWindowAndroidFactory = factory;
397     }
398
399     @VisibleForTesting
400     public static void setAppMenuHandlerFactory(AppMenuHandlerFactory factory) {
401         sAppMenuHandlerFactory = factory;
402     }
403 }