Advertisement
Guest User

CordovaActivity.java

a guest
Oct 14th, 2014
519
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 29.77 KB | None | 0 0
  1. /*
  2. Licensed to the Apache Software Foundation (ASF) under one
  3. or more contributor license agreements. See the NOTICE file
  4. distributed with this work for additional information
  5. regarding copyright ownership. The ASF licenses this file
  6. to you under the Apache License, Version 2.0 (the
  7. "License"); you may not use this file except in compliance
  8. with the License. You may obtain a copy of the License at
  9. http://www.apache.org/licenses/LICENSE-2.0
  10. Unless required by applicable law or agreed to in writing,
  11. software distributed under the License is distributed on an
  12. "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  13. KIND, either express or implied. See the License for the
  14. specific language governing permissions and limitations
  15. under the License.
  16. */
  17. package org.apache.cordova;
  18. import java.util.ArrayList;
  19. import java.util.HashMap;
  20. import java.util.concurrent.ExecutorService;
  21. import java.util.concurrent.Executors;
  22. import org.apache.cordova.CordovaInterface;
  23. import org.apache.cordova.CordovaPlugin;
  24. import org.apache.cordova.LOG;
  25. import org.json.JSONException;
  26. import org.json.JSONObject;
  27. import android.annotation.SuppressLint;
  28. import android.app.Activity;
  29. import android.app.AlertDialog;
  30. import android.app.Dialog;
  31. import android.app.ProgressDialog;
  32. import android.content.Context;
  33. import android.content.DialogInterface;
  34. import android.content.Intent;
  35. import android.graphics.Color;
  36. import android.media.AudioManager;
  37. import android.net.Uri;
  38. import android.os.Bundle;
  39. import android.os.Handler;
  40. import android.util.Log;
  41. import android.view.Display;
  42. import android.view.KeyEvent;
  43. import android.view.Menu;
  44. import android.view.MenuItem;
  45. import android.view.View;
  46. import android.view.ViewGroup;
  47. import android.view.ViewParent;
  48. import android.view.Window;
  49. import android.view.WindowManager;
  50. import android.webkit.ValueCallback;
  51. import android.webkit.WebViewClient;
  52. import android.widget.LinearLayout;
  53. /**
  54. * This class is the main Android activity that represents the Cordova
  55. * application. It should be extended by the user to load the specific
  56. * html file that contains the application.
  57. *
  58. * As an example:
  59. *
  60. * <pre>
  61. * package org.apache.cordova.examples;
  62. *
  63. * import android.os.Bundle;
  64. * import org.apache.cordova.*;
  65. *
  66. * public class Example extends CordovaActivity {
  67. * &#64;Override
  68. * public void onCreate(Bundle savedInstanceState) {
  69. * super.onCreate(savedInstanceState);
  70. * super.init();
  71. * // Load your application
  72. * loadUrl(launchUrl);
  73. * }
  74. * }
  75. * </pre>
  76. *
  77. * Cordova xml configuration: Cordova uses a configuration file at
  78. * res/xml/config.xml to specify its settings. See "The config.xml File"
  79. * guide in cordova-docs at http://cordova.apache.org/docs for the documentation
  80. * for the configuration. The use of the set*Property() methods is
  81. * deprecated in favor of the config.xml file.
  82. *
  83. */
  84. public class CordovaActivity extends Activity implements CordovaInterface {
  85. public static String TAG = "CordovaActivity";
  86. // The webview for our app
  87. protected CordovaWebView appView;
  88. @Deprecated // unused.
  89. protected CordovaWebViewClient webViewClient;
  90. @Deprecated // Will be removed. Use findViewById() to retrieve views.
  91. protected LinearLayout root;
  92. protected ProgressDialog spinnerDialog = null;
  93. private final ExecutorService threadPool = Executors.newCachedThreadPool();
  94. private static int ACTIVITY_STARTING = 0;
  95. private static int ACTIVITY_RUNNING = 1;
  96. private static int ACTIVITY_EXITING = 2;
  97. private int activityState = 0; // 0=starting, 1=running (after 1st resume), 2=shutting down
  98. // Plugin to call when activity result is received
  99. protected CordovaPlugin activityResultCallback = null;
  100. protected boolean activityResultKeepRunning;
  101. /*
  102. * The variables below are used to cache some of the activity properties.
  103. */
  104. // Draw a splash screen using an image located in the drawable resource directory.
  105. // This is not the same as calling super.loadSplashscreen(url)
  106. protected int splashscreen = 0;
  107. protected int splashscreenTime = 3000;
  108. // LoadUrl timeout value in msec (default of 20 sec)
  109. protected int loadUrlTimeoutValue = 20000;
  110. // Keep app running when pause is received. (default = true)
  111. // If true, then the JavaScript and native code continue to run in the background
  112. // when another application (activity) is started.
  113. protected boolean keepRunning = true;
  114. private String initCallbackClass;
  115. // Read from config.xml:
  116. protected CordovaPreferences preferences;
  117. protected Whitelist internalWhitelist;
  118. protected Whitelist externalWhitelist;
  119. protected String launchUrl;
  120. protected ArrayList<PluginEntry> pluginEntries;
  121. /**
  122. * Sets the authentication token.
  123. *
  124. * @param authenticationToken
  125. * @param host
  126. * @param realm
  127. */
  128. public void setAuthenticationToken(AuthenticationToken authenticationToken, String host, String realm) {
  129. if (this.appView != null && this.appView.viewClient != null) {
  130. this.appView.viewClient.setAuthenticationToken(authenticationToken, host, realm);
  131. }
  132. }
  133. /**
  134. * Removes the authentication token.
  135. *
  136. * @param host
  137. * @param realm
  138. *
  139. * @return the authentication token or null if did not exist
  140. */
  141. public AuthenticationToken removeAuthenticationToken(String host, String realm) {
  142. if (this.appView != null && this.appView.viewClient != null) {
  143. return this.appView.viewClient.removeAuthenticationToken(host, realm);
  144. }
  145. return null;
  146. }
  147. /**
  148. * Gets the authentication token.
  149. *
  150. * In order it tries:
  151. * 1- host + realm
  152. * 2- host
  153. * 3- realm
  154. * 4- no host, no realm
  155. *
  156. * @param host
  157. * @param realm
  158. *
  159. * @return the authentication token
  160. */
  161. public AuthenticationToken getAuthenticationToken(String host, String realm) {
  162. if (this.appView != null && this.appView.viewClient != null) {
  163. return this.appView.viewClient.getAuthenticationToken(host, realm);
  164. }
  165. return null;
  166. }
  167. /**
  168. * Clear all authentication tokens.
  169. */
  170. public void clearAuthenticationTokens() {
  171. if (this.appView != null && this.appView.viewClient != null) {
  172. this.appView.viewClient.clearAuthenticationTokens();
  173. }
  174. }
  175. /**
  176. * Called when the activity is first created.
  177. */
  178. @Override
  179. public void onCreate(Bundle savedInstanceState) {
  180. LOG.i(TAG, "Apache Cordova native platform version " + CordovaWebView.CORDOVA_VERSION + " is starting");
  181. LOG.d(TAG, "CordovaActivity.onCreate()");
  182. // need to activate preferences before super.onCreate to avoid "requestFeature() must be called before adding content" exception
  183. loadConfig();
  184. if(!preferences.getBoolean("ShowTitle", false))
  185. {
  186. getWindow().requestFeature(Window.FEATURE_NO_TITLE);
  187. }
  188. if(preferences.getBoolean("SetFullscreen", false))
  189. {
  190. Log.d(TAG, "The SetFullscreen configuration is deprecated in favor of Fullscreen, and will be removed in a future version.");
  191. getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
  192. WindowManager.LayoutParams.FLAG_FULLSCREEN);
  193. } else if (preferences.getBoolean("Fullscreen", false)) {
  194. getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
  195. WindowManager.LayoutParams.FLAG_FULLSCREEN);
  196. } else {
  197. getWindow().setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN,
  198. WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
  199. }
  200. super.onCreate(savedInstanceState);
  201. if(savedInstanceState != null)
  202. {
  203. initCallbackClass = savedInstanceState.getString("callbackClass");
  204. }
  205. }
  206. @SuppressWarnings("deprecation")
  207. protected void loadConfig() {
  208. ConfigXmlParser parser = new ConfigXmlParser();
  209. parser.parse(this);
  210. preferences = parser.getPreferences();
  211. preferences.setPreferencesBundle(getIntent().getExtras());
  212. preferences.copyIntoIntentExtras(this);
  213. internalWhitelist = parser.getInternalWhitelist();
  214. externalWhitelist = parser.getExternalWhitelist();
  215. launchUrl = parser.getLaunchUrl();
  216. pluginEntries = parser.getPluginEntries();
  217. Config.parser = parser;
  218. }
  219. @SuppressWarnings("deprecation")
  220. protected void createViews() {
  221. // This builds the view. We could probably get away with NOT having a LinearLayout, but I like having a bucket!
  222. LOG.d(TAG, "CordovaActivity.createViews()");
  223. Display display = getWindowManager().getDefaultDisplay();
  224. int width = display.getWidth();
  225. int height = display.getHeight();
  226. root = new LinearLayoutSoftKeyboardDetect(this, width, height);
  227. root.setOrientation(LinearLayout.VERTICAL);
  228. root.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
  229. ViewGroup.LayoutParams.MATCH_PARENT, 0.0F));
  230. appView.setId(100);
  231. appView.setLayoutParams(new LinearLayout.LayoutParams(
  232. ViewGroup.LayoutParams.MATCH_PARENT,
  233. ViewGroup.LayoutParams.MATCH_PARENT,
  234. 1.0F));
  235. // Add web view but make it invisible while loading URL
  236. appView.setVisibility(View.INVISIBLE);
  237. // need to remove appView from any existing parent before invoking root.addView(appView)
  238. ViewParent parent = appView.getParent();
  239. if ((parent != null) && (parent != root)) {
  240. LOG.d(TAG, "removing appView from existing parent");
  241. ViewGroup parentGroup = (ViewGroup) parent;
  242. parentGroup.removeView(appView);
  243. }
  244. root.addView((View) appView);
  245. setContentView(root);
  246. int backgroundColor = preferences.getInteger("BackgroundColor", Color.BLACK);
  247. root.setBackgroundColor(backgroundColor);
  248. }
  249. /**
  250. * Get the Android activity.
  251. */
  252. @Override public Activity getActivity() {
  253. return this;
  254. }
  255. /**
  256. * Construct the default web view object.
  257. *
  258. * This is intended to be overridable by subclasses of CordovaIntent which
  259. * require a more specialized web view.
  260. */
  261. protected CordovaWebView makeWebView() {
  262. return new CordovaWebView(CordovaActivity.this);
  263. }
  264. /**
  265. * Construct the client for the default web view object.
  266. *
  267. * This is intended to be overridable by subclasses of CordovaIntent which
  268. * require a more specialized web view.
  269. *
  270. * @param webView the default constructed web view object
  271. */
  272. protected CordovaWebViewClient makeWebViewClient(CordovaWebView webView) {
  273. return webView.makeWebViewClient(this);
  274. }
  275. /**
  276. * Construct the chrome client for the default web view object.
  277. *
  278. * This is intended to be overridable by subclasses of CordovaIntent which
  279. * require a more specialized web view.
  280. *
  281. * @param webView the default constructed web view object
  282. */
  283. protected CordovaChromeClient makeChromeClient(CordovaWebView webView) {
  284. return webView.makeWebChromeClient(this);
  285. }
  286. public void init() {
  287. this.init(appView, null, null);
  288. }
  289. @SuppressLint("NewApi")
  290. @Deprecated // Call init() instead and override makeWebView() to customize.
  291. public void init(CordovaWebView webView, CordovaWebViewClient webViewClient, CordovaChromeClient webChromeClient) {
  292. LOG.d(TAG, "CordovaActivity.init()");
  293. appView = webView != null ? webView : makeWebView();
  294. if (appView.pluginManager == null) {
  295. appView.init(this, webViewClient != null ? webViewClient : makeWebViewClient(appView),
  296. webChromeClient != null ? webChromeClient : makeChromeClient(appView),
  297. pluginEntries, internalWhitelist, externalWhitelist, preferences);
  298. }
  299. // TODO: Have the views set this themselves.
  300. if (preferences.getBoolean("DisallowOverscroll", false)) {
  301. appView.setOverScrollMode(View.OVER_SCROLL_NEVER);
  302. }
  303. createViews();
  304. // TODO: Make this a preference (CB-6153)
  305. // Setup the hardware volume controls to handle volume control
  306. setVolumeControlStream(AudioManager.STREAM_MUSIC);
  307. }
  308. /**
  309. * Load the url into the webview.
  310. */
  311. public void loadUrl(String url) {
  312. if (appView == null) {
  313. init();
  314. }
  315. this.splashscreenTime = preferences.getInteger("SplashScreenDelay", this.splashscreenTime);
  316. String splash = preferences.getString("SplashScreen", null);
  317. if(this.splashscreenTime > 0 && splash != null)
  318. {
  319. this.splashscreen = getResources().getIdentifier(splash, "drawable", getClass().getPackage().getName());;
  320. if(this.splashscreen != 0)
  321. {
  322. this.showSplashScreen(this.splashscreenTime);
  323. }
  324. }
  325. // If keepRunning
  326. this.keepRunning = preferences.getBoolean("KeepRunning", true);
  327. //Check if the view is attached to anything
  328. if(appView.getParent() != null)
  329. {
  330. // Then load the spinner
  331. this.loadSpinner();
  332. }
  333. //Load the correct splashscreen
  334. if(this.splashscreen != 0)
  335. {
  336. this.appView.loadUrl(url, this.splashscreenTime);
  337. }
  338. else
  339. {
  340. this.appView.loadUrl(url);
  341. }
  342. }
  343. /**
  344. * Load the url into the webview after waiting for period of time.
  345. * This is used to display the splashscreen for certain amount of time.
  346. *
  347. * @param url
  348. * @param time The number of ms to wait before loading webview
  349. */
  350. public void loadUrl(final String url, int time) {
  351. this.splashscreenTime = time;
  352. this.loadUrl(url);
  353. }
  354. /*
  355. * Load the spinner
  356. */
  357. void loadSpinner() {
  358. // If loadingDialog property, then show the App loading dialog for first page of app
  359. String loading = null;
  360. if ((this.appView == null) || !this.appView.canGoBack()) {
  361. loading = preferences.getString("LoadingDialog", null);
  362. }
  363. else {
  364. loading = preferences.getString("LoadingPageDialog", null);
  365. }
  366. if (loading != null) {
  367. String title = "";
  368. String message = "Loading Application...";
  369. if (loading.length() > 0) {
  370. int comma = loading.indexOf(',');
  371. if (comma > 0) {
  372. title = loading.substring(0, comma);
  373. message = loading.substring(comma + 1);
  374. }
  375. else {
  376. title = "";
  377. message = loading;
  378. }
  379. }
  380. this.spinnerStart(title, message);
  381. }
  382. }
  383. @Deprecated
  384. public void cancelLoadUrl() {
  385. }
  386. /**
  387. * Clear the resource cache.
  388. */
  389. @Deprecated // Call method on appView directly.
  390. public void clearCache() {
  391. if (appView == null) {
  392. init();
  393. }
  394. this.appView.clearCache(true);
  395. }
  396. /**
  397. * Clear web history in this web view.
  398. */
  399. @Deprecated // Call method on appView directly.
  400. public void clearHistory() {
  401. this.appView.clearHistory();
  402. }
  403. /**
  404. * Go to previous page in history. (We manage our own history)
  405. *
  406. * @return true if we went back, false if we are already at top
  407. */
  408. @Deprecated // Call method on appView directly.
  409. public boolean backHistory() {
  410. if (this.appView != null) {
  411. return appView.backHistory();
  412. }
  413. return false;
  414. }
  415. /**
  416. * Get boolean property for activity.
  417. */
  418. @Deprecated // Call method on preferences directly.
  419. public boolean getBooleanProperty(String name, boolean defaultValue) {
  420. return preferences.getBoolean(name, defaultValue);
  421. }
  422. /**
  423. * Get int property for activity.
  424. */
  425. @Deprecated // Call method on preferences directly.
  426. public int getIntegerProperty(String name, int defaultValue) {
  427. return preferences.getInteger(name, defaultValue);
  428. }
  429. /**
  430. * Get string property for activity.
  431. */
  432. @Deprecated // Call method on preferences directly.
  433. public String getStringProperty(String name, String defaultValue) {
  434. return preferences.getString(name, defaultValue);
  435. }
  436. /**
  437. * Get double property for activity.
  438. */
  439. @Deprecated // Call method on preferences directly.
  440. public double getDoubleProperty(String name, double defaultValue) {
  441. return preferences.getDouble(name, defaultValue);
  442. }
  443. /**
  444. * Set boolean property on activity.
  445. * This method has been deprecated in 3.0 and will be removed at a future
  446. * time. Please use config.xml instead.
  447. *
  448. * @param name
  449. * @param value
  450. * @deprecated
  451. */
  452. @Deprecated
  453. public void setBooleanProperty(String name, boolean value) {
  454. Log.d(TAG, "Setting boolean properties in CordovaActivity will be deprecated in 3.0 on July 2013, please use config.xml");
  455. this.getIntent().putExtra(name.toLowerCase(), value);
  456. }
  457. /**
  458. * Set int property on activity.
  459. * This method has been deprecated in 3.0 and will be removed at a future
  460. * time. Please use config.xml instead.
  461. *
  462. * @param name
  463. * @param value
  464. * @deprecated
  465. */
  466. @Deprecated
  467. public void setIntegerProperty(String name, int value) {
  468. Log.d(TAG, "Setting integer properties in CordovaActivity will be deprecated in 3.0 on July 2013, please use config.xml");
  469. this.getIntent().putExtra(name.toLowerCase(), value);
  470. }
  471. /**
  472. * Set string property on activity.
  473. * This method has been deprecated in 3.0 and will be removed at a future
  474. * time. Please use config.xml instead.
  475. *
  476. * @param name
  477. * @param value
  478. * @deprecated
  479. */
  480. @Deprecated
  481. public void setStringProperty(String name, String value) {
  482. Log.d(TAG, "Setting string properties in CordovaActivity will be deprecated in 3.0 on July 2013, please use config.xml");
  483. this.getIntent().putExtra(name.toLowerCase(), value);
  484. }
  485. /**
  486. * Set double property on activity.
  487. * This method has been deprecated in 3.0 and will be removed at a future
  488. * time. Please use config.xml instead.
  489. *
  490. * @param name
  491. * @param value
  492. * @deprecated
  493. */
  494. @Deprecated
  495. public void setDoubleProperty(String name, double value) {
  496. Log.d(TAG, "Setting double properties in CordovaActivity will be deprecated in 3.0 on July 2013, please use config.xml");
  497. this.getIntent().putExtra(name.toLowerCase(), value);
  498. }
  499. /**
  500. * Called when the system is about to start resuming a previous activity.
  501. */
  502. @Override
  503. protected void onPause() {
  504. super.onPause();
  505. LOG.d(TAG, "Paused the application!");
  506. // Don't process pause if shutting down, since onDestroy() will be called
  507. if (this.activityState == ACTIVITY_EXITING) {
  508. return;
  509. }
  510. if (this.appView == null) {
  511. return;
  512. }
  513. else
  514. {
  515. this.appView.handlePause(this.keepRunning);
  516. }
  517. // hide the splash screen to avoid leaking a window
  518. this.removeSplashScreen();
  519. }
  520. /**
  521. * Called when the activity receives a new intent
  522. **/
  523. @Override
  524. protected void onNewIntent(Intent intent) {
  525. super.onNewIntent(intent);
  526. //Forward to plugins
  527. if (this.appView != null)
  528. this.appView.onNewIntent(intent);
  529. }
  530. /**
  531. * Called when the activity will start interacting with the user.
  532. */
  533. @Override
  534. protected void onResume() {
  535. super.onResume();
  536. LOG.d(TAG, "Resuming the App");
  537. if (this.activityState == ACTIVITY_STARTING) {
  538. this.activityState = ACTIVITY_RUNNING;
  539. return;
  540. }
  541. if (this.appView == null) {
  542. return;
  543. }
  544. // Force window to have focus, so application always
  545. // receive user input. Workaround for some devices (Samsung Galaxy Note 3 at least)
  546. this.getWindow().getDecorView().requestFocus();
  547. this.appView.handleResume(this.keepRunning, this.activityResultKeepRunning);
  548. // If app doesn't want to run in background
  549. if (!this.keepRunning || this.activityResultKeepRunning) {
  550. // Restore multitasking state
  551. if (this.activityResultKeepRunning) {
  552. this.keepRunning = this.activityResultKeepRunning;
  553. this.activityResultKeepRunning = false;
  554. }
  555. }
  556. }
  557. /**
  558. * The final call you receive before your activity is destroyed.
  559. */
  560. @Override
  561. public void onDestroy() {
  562. LOG.d(TAG, "CordovaActivity.onDestroy()");
  563. super.onDestroy();
  564. // hide the splash screen to avoid leaking a window
  565. this.removeSplashScreen();
  566. if (this.appView != null) {
  567. appView.handleDestroy();
  568. }
  569. else {
  570. this.activityState = ACTIVITY_EXITING;
  571. }
  572. }
  573. /**
  574. * Send a message to all plugins.
  575. */
  576. public void postMessage(String id, Object data) {
  577. if (this.appView != null) {
  578. this.appView.postMessage(id, data);
  579. }
  580. }
  581. /**
  582. * @deprecated
  583. * Add services to res/xml/plugins.xml instead.
  584. *
  585. * Add a class that implements a service.
  586. */
  587. @Deprecated
  588. public void addService(String serviceType, String className) {
  589. if (this.appView != null && this.appView.pluginManager != null) {
  590. this.appView.pluginManager.addService(serviceType, className);
  591. }
  592. }
  593. /**
  594. * Send JavaScript statement back to JavaScript.
  595. * (This is a convenience method)
  596. *
  597. * @param statement
  598. */
  599. @Deprecated // Call method on appView directly.
  600. public void sendJavascript(String statement) {
  601. if (this.appView != null) {
  602. this.appView.bridge.getMessageQueue().addJavaScript(statement);
  603. }
  604. }
  605. /**
  606. * Show the spinner. Must be called from the UI thread.
  607. *
  608. * @param title Title of the dialog
  609. * @param message The message of the dialog
  610. */
  611. public void spinnerStart(final String title, final String message) {
  612. if (this.spinnerDialog != null) {
  613. this.spinnerDialog.dismiss();
  614. this.spinnerDialog = null;
  615. }
  616. final CordovaActivity me = this;
  617. this.spinnerDialog = ProgressDialog.show(CordovaActivity.this, title, message, true, true,
  618. new DialogInterface.OnCancelListener() {
  619. public void onCancel(DialogInterface dialog) {
  620. me.spinnerDialog = null;
  621. }
  622. });
  623. }
  624. /**
  625. * Stop spinner - Must be called from UI thread
  626. */
  627. public void spinnerStop() {
  628. if (this.spinnerDialog != null && this.spinnerDialog.isShowing()) {
  629. this.spinnerDialog.dismiss();
  630. this.spinnerDialog = null;
  631. }
  632. }
  633. /**
  634. * End this activity by calling finish for activity
  635. */
  636. public void endActivity() {
  637. this.activityState = ACTIVITY_EXITING;
  638. super.finish();
  639. }
  640. /**
  641. * Launch an activity for which you would like a result when it finished. When this activity exits,
  642. * your onActivityResult() method will be called.
  643. *
  644. * @param command The command object
  645. * @param intent The intent to start
  646. * @param requestCode The request code that is passed to callback to identify the activity
  647. */
  648. public void startActivityForResult(CordovaPlugin command, Intent intent, int requestCode) {
  649. this.activityResultCallback = command;
  650. this.activityResultKeepRunning = this.keepRunning;
  651. // If multitasking turned on, then disable it for activities that return results
  652. if (command != null) {
  653. this.keepRunning = false;
  654. }
  655. // Start activity
  656. super.startActivityForResult(intent, requestCode);
  657. }
  658. /**
  659. * Called when an activity you launched exits, giving you the requestCode you started it with,
  660. * the resultCode it returned, and any additional data from it.
  661. *
  662. * @param requestCode The request code originally supplied to startActivityForResult(),
  663. * allowing you to identify who this result came from.
  664. * @param resultCode The integer result code returned by the child activity through its setResult().
  665. * @param data An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
  666. */
  667. @Override
  668. protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
  669. LOG.d(TAG, "Incoming Result");
  670. super.onActivityResult(requestCode, resultCode, intent);
  671. Log.d(TAG, "Request code = " + requestCode);
  672. if (appView != null && requestCode == CordovaChromeClient.FILECHOOSER_RESULTCODE) {
  673. ValueCallback<Uri> mUploadMessage = this.appView.getWebChromeClient().getValueCallback();
  674. Log.d(TAG, "did we get here?");
  675. if (null == mUploadMessage)
  676. return;
  677. Uri result = intent == null || resultCode != Activity.RESULT_OK ? null : intent.getData();
  678. Log.d(TAG, "result = " + result);
  679. mUploadMessage.onReceiveValue(result);
  680. mUploadMessage = null;
  681. }
  682. CordovaPlugin callback = this.activityResultCallback;
  683. if(callback == null && initCallbackClass != null) {
  684. // The application was restarted, but had defined an initial callback
  685. // before being shut down.
  686. this.activityResultCallback = appView.pluginManager.getPlugin(initCallbackClass);
  687. callback = this.activityResultCallback;
  688. }
  689. if(callback != null) {
  690. LOG.d(TAG, "We have a callback to send this result to");
  691. callback.onActivityResult(requestCode, resultCode, intent);
  692. }
  693. }
  694. public void setActivityResultCallback(CordovaPlugin plugin) {
  695. this.activityResultCallback = plugin;
  696. }
  697. /**
  698. * Report an error to the host application. These errors are unrecoverable (i.e. the main resource is unavailable).
  699. * The errorCode parameter corresponds to one of the ERROR_* constants.
  700. *
  701. * @param errorCode The error code corresponding to an ERROR_* value.
  702. * @param description A String describing the error.
  703. * @param failingUrl The url that failed to load.
  704. */
  705. public void onReceivedError(final int errorCode, final String description, final String failingUrl) {
  706. final CordovaActivity me = this;
  707. // If errorUrl specified, then load it
  708. final String errorUrl = preferences.getString("errorUrl", null);
  709. if ((errorUrl != null) && (errorUrl.startsWith("file://") || internalWhitelist.isUrlWhiteListed(errorUrl)) && (!failingUrl.equals(errorUrl))) {
  710. // Load URL on UI thread
  711. me.runOnUiThread(new Runnable() {
  712. public void run() {
  713. // Stop "app loading" spinner if showing
  714. me.spinnerStop();
  715. me.appView.showWebPage(errorUrl, false, true, null);
  716. }
  717. });
  718. }
  719. // If not, then display error dialog
  720. else {
  721. final boolean exit = !(errorCode == WebViewClient.ERROR_HOST_LOOKUP);
  722. me.runOnUiThread(new Runnable() {
  723. public void run() {
  724. if (exit) {
  725. me.appView.setVisibility(View.GONE);
  726. me.displayError("Application Error", description + " (" + failingUrl + ")", "OK", exit);
  727. }
  728. }
  729. });
  730. }
  731. }
  732. /**
  733. * Display an error dialog and optionally exit application.
  734. */
  735. public void displayError(final String title, final String message, final String button, final boolean exit) {
  736. final CordovaActivity me = this;
  737. me.runOnUiThread(new Runnable() {
  738. public void run() {
  739. try {
  740. AlertDialog.Builder dlg = new AlertDialog.Builder(me);
  741. dlg.setMessage(message);
  742. dlg.setTitle(title);
  743. dlg.setCancelable(false);
  744. dlg.setPositiveButton(button,
  745. new AlertDialog.OnClickListener() {
  746. public void onClick(DialogInterface dialog, int which) {
  747. dialog.dismiss();
  748. if (exit) {
  749. me.endActivity();
  750. }
  751. }
  752. });
  753. dlg.create();
  754. dlg.show();
  755. } catch (Exception e) {
  756. finish();
  757. }
  758. }
  759. });
  760. }
  761. /**
  762. * Determine if URL is in approved list of URLs to load.
  763. */
  764. @Deprecated // Use whitelist object directly.
  765. public boolean isUrlWhiteListed(String url) {
  766. return internalWhitelist.isUrlWhiteListed(url);
  767. }
  768. /*
  769. * Hook in Cordova for menu plugins
  770. */
  771. @Override
  772. public boolean onCreateOptionsMenu(Menu menu) {
  773. this.postMessage("onCreateOptionsMenu", menu);
  774. return super.onCreateOptionsMenu(menu);
  775. }
  776. @Override
  777. public boolean onPrepareOptionsMenu(Menu menu) {
  778. this.postMessage("onPrepareOptionsMenu", menu);
  779. return true;
  780. }
  781. @Override
  782. public boolean onOptionsItemSelected(MenuItem item) {
  783. this.postMessage("onOptionsItemSelected", item);
  784. return true;
  785. }
  786. /**
  787. * Get Activity context.
  788. */
  789. @Deprecated
  790. public Context getContext() {
  791. LOG.d(TAG, "This will be deprecated December 2012");
  792. return this;
  793. }
  794. /**
  795. * Load the specified URL in the Cordova webview or a new browser instance.
  796. *
  797. * NOTE: If openExternal is false, only URLs listed in whitelist can be loaded.
  798. *
  799. * @param url The url to load.
  800. * @param openExternal Load url in browser instead of Cordova webview.
  801. * @param clearHistory Clear the history stack, so new page becomes top of history
  802. * @param params Parameters for new app
  803. */
  804. @Deprecated // Call method on appView directly.
  805. public void showWebPage(String url, boolean openExternal, boolean clearHistory, HashMap<String, Object> params) {
  806. if (this.appView != null) {
  807. appView.showWebPage(url, openExternal, clearHistory, params);
  808. }
  809. }
  810. protected Dialog splashDialog;
  811. /**
  812. * Removes the Dialog that displays the splash screen
  813. */
  814. public void removeSplashScreen() {
  815. if (splashDialog != null && splashDialog.isShowing()) {
  816. splashDialog.dismiss();
  817. splashDialog = null;
  818. }
  819. }
  820. /**
  821. * Shows the splash screen over the full Activity
  822. */
  823. @SuppressWarnings("deprecation")
  824. protected void showSplashScreen(final int time) {
  825. final CordovaActivity that = this;
  826. Runnable runnable = new Runnable() {
  827. public void run() {
  828. // Get reference to display
  829. Display display = getWindowManager().getDefaultDisplay();
  830. // Create the layout for the dialog
  831. LinearLayout root = new LinearLayout(that.getActivity());
  832. root.setMinimumHeight(display.getHeight());
  833. root.setMinimumWidth(display.getWidth());
  834. root.setOrientation(LinearLayout.VERTICAL);
  835. root.setBackgroundColor(preferences.getInteger("backgroundColor", Color.BLACK));
  836. root.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
  837. ViewGroup.LayoutParams.MATCH_PARENT, 0.0F));
  838. root.setBackgroundResource(that.splashscreen);
  839. // Create and show the dialog
  840. splashDialog = new Dialog(that, android.R.style.Theme_Translucent_NoTitleBar);
  841. // check to see if the splash screen should be full screen
  842. if ((getWindow().getAttributes().flags & WindowManager.LayoutParams.FLAG_FULLSCREEN)
  843. == WindowManager.LayoutParams.FLAG_FULLSCREEN) {
  844. splashDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
  845. WindowManager.LayoutParams.FLAG_FULLSCREEN);
  846. }
  847. splashDialog.setContentView(root);
  848. splashDialog.setCancelable(false);
  849. splashDialog.show();
  850. // Set Runnable to remove splash screen just in case
  851. final Handler handler = new Handler();
  852. handler.postDelayed(new Runnable() {
  853. public void run() {
  854. removeSplashScreen();
  855. }
  856. }, time);
  857. }
  858. };
  859. this.runOnUiThread(runnable);
  860. }
  861. @Override
  862. public boolean onKeyUp(int keyCode, KeyEvent event)
  863. {
  864. if (appView != null && (appView.isCustomViewShowing() || appView.getFocusedChild() != null ) &&
  865. (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU)) {
  866. return appView.onKeyUp(keyCode, event);
  867. } else {
  868. return super.onKeyUp(keyCode, event);
  869. }
  870. }
  871. /*
  872. * Android 2.x needs to be able to check where the cursor is. Android 4.x does not
  873. *
  874. * (non-Javadoc)
  875. * @see android.app.Activity#onKeyDown(int, android.view.KeyEvent)
  876. */
  877. @Override
  878. public boolean onKeyDown(int keyCode, KeyEvent event)
  879. {
  880. //Determine if the focus is on the current view or not
  881. if (appView != null && appView.getFocusedChild() != null && (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU)) {
  882. return appView.onKeyDown(keyCode, event);
  883. }
  884. else
  885. return super.onKeyDown(keyCode, event);
  886. }
  887. /**
  888. * Called when a message is sent to plugin.
  889. *
  890. * @param id The message id
  891. * @param data The message data
  892. * @return Object or null
  893. */
  894. public Object onMessage(String id, Object data) {
  895. if (!"onScrollChanged".equals(id)) {
  896. LOG.d(TAG, "onMessage(" + id + "," + data + ")");
  897. }
  898. if ("splashscreen".equals(id)) {
  899. if ("hide".equals(data.toString())) {
  900. this.removeSplashScreen();
  901. }
  902. else {
  903. // If the splash dialog is showing don't try to show it again
  904. if (this.splashDialog == null || !this.splashDialog.isShowing()) {
  905. String splashResource = preferences.getString("SplashScreen", null);
  906. if (splashResource != null) {
  907. splashscreen = getResources().getIdentifier(splashResource, "drawable", getClass().getPackage().getName());
  908. }
  909. this.showSplashScreen(this.splashscreenTime);
  910. }
  911. }
  912. }
  913. else if ("spinner".equals(id)) {
  914. if ("stop".equals(data.toString())) {
  915. this.spinnerStop();
  916. this.appView.setVisibility(View.VISIBLE);
  917. }
  918. }
  919. else if ("onReceivedError".equals(id)) {
  920. JSONObject d = (JSONObject) data;
  921. try {
  922. this.onReceivedError(d.getInt("errorCode"), d.getString("description"), d.getString("url"));
  923. } catch (JSONException e) {
  924. e.printStackTrace();
  925. }
  926. }
  927. else if ("exit".equals(id)) {
  928. this.endActivity();
  929. }
  930. return null;
  931. }
  932. public ExecutorService getThreadPool() {
  933. return threadPool;
  934. }
  935. protected void onSaveInstanceState(Bundle outState)
  936. {
  937. super.onSaveInstanceState(outState);
  938. if(this.activityResultCallback != null)
  939. {
  940. String cClass = this.activityResultCallback.getClass().getName();
  941. outState.putString("callbackClass", cClass);
  942. }
  943. }
  944. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement