Browse Source

import changes from rmottola/Arctic-Fox:

- remove mobile-android (cf8ef1e27)
- remove also android examples (94f68c0e5)
- remove android mozglue (d0114f339)
pull/2/head
Roy Tam 3 years ago
parent
commit
ec05a9b22f
  1. 1
      build/mach_bootstrap.py
  2. 51
      config/android-common.mk
  3. 47
      configure.in
  4. 988
      embedding/android/GoannaSmsManager.java
  5. 23
      embedding/android/goannaview_example/AndroidManifest.xml.in
  6. 14
      embedding/android/goannaview_example/GoannaViewExample.java
  7. 65
      embedding/android/goannaview_example/Makefile.in
  8. 12
      embedding/android/goannaview_example/main.xml
  9. 0
      embedding/android/goannaview_example/moz.build
  10. 3
      embedding/moz.build
  11. 373
      mobile/android/LICENSE
  12. 11
      mobile/android/Makefile.in
  13. 21
      mobile/android/app.mozbuild
  14. BIN
      mobile/android/app/mobile.ico
  15. 819
      mobile/android/app/mobile.js
  16. 19
      mobile/android/app/moz.build
  17. 592
      mobile/android/base/ANRReporter.java
  18. 107
      mobile/android/base/AboutPages.java
  19. 127
      mobile/android/base/ActionModeCompat.java
  20. 177
      mobile/android/base/ActionModeCompatView.java
  21. 38
      mobile/android/base/ActivityHandlerHelper.java
  22. 125
      mobile/android/base/AlertNotification.java
  23. 391
      mobile/android/base/AndroidGamepadManager.java
  24. 463
      mobile/android/base/AndroidManifest.xml.in
  25. 296
      mobile/android/base/AppConstants.java.in
  26. 25
      mobile/android/base/AppNotificationClient.java
  27. 84
      mobile/android/base/Assert.java
  28. 154
      mobile/android/base/BaseGoannaInterface.java
  29. 3656
      mobile/android/base/BrowserApp.java
  30. 440
      mobile/android/base/BrowserLocaleManager.java
  31. 499
      mobile/android/base/ChromeCast.java
  32. 2014
      mobile/android/base/ContactService.java
  33. 15
      mobile/android/base/ContextGetter.java
  34. 468
      mobile/android/base/CrashHandler.java
  35. 88
      mobile/android/base/CustomEditText.java
  36. 133
      mobile/android/base/DataReportingNotification.java
  37. 349
      mobile/android/base/DoorHangerPopup.java
  38. 211
      mobile/android/base/DownloadsIntegration.java
  39. 167
      mobile/android/base/DynamicToolbar.java
  40. 248
      mobile/android/base/EditBookmarkDialog.java
  41. 292
      mobile/android/base/EventDispatcher.java
  42. 228
      mobile/android/base/FilePicker.java
  43. 275
      mobile/android/base/FilePickerResultHandler.java
  44. 259
      mobile/android/base/FindInPageBar.java
  45. 447
      mobile/android/base/FormAssistPopup.java
  46. 159
      mobile/android/base/GlobalHistory.java
  47. 434
      mobile/android/base/GoannaAccessibility.java
  48. 100
      mobile/android/base/GoannaActivity.java
  49. 10
      mobile/android/base/GoannaActivityStatus.java
  50. 2618
      mobile/android/base/GoannaApp.java
  51. 2689
      mobile/android/base/GoannaAppShell.java
  52. 168
      mobile/android/base/GoannaApplication.java
  53. 197
      mobile/android/base/GoannaBatteryManager.java
  54. 89
      mobile/android/base/GoannaConnectivityReceiver.java
  55. 1249
      mobile/android/base/GoannaEditable.java
  56. 21
      mobile/android/base/GoannaEditableClient.java
  57. 30
      mobile/android/base/GoannaEditableListener.java
  58. 850
      mobile/android/base/GoannaEvent.java
  59. 25
      mobile/android/base/GoannaHalDefines.java
  60. 1070
      mobile/android/base/GoannaInputConnection.java
  61. 218
      mobile/android/base/GoannaJavaSampler.java
  62. 27
      mobile/android/base/GoannaMediaPlayer.java
  63. 19
      mobile/android/base/GoannaMessageReceiver.java
  64. 332
      mobile/android/base/GoannaNetworkManager.java
  65. 888
      mobile/android/base/GoannaProfile.java
  66. 228
      mobile/android/base/GoannaProfileDirectories.java
  67. 149
      mobile/android/base/GoannaProfilesProvider.java
  68. 384
      mobile/android/base/GoannaScreenOrientation.java
  69. 263
      mobile/android/base/GoannaSharedPrefs.java
  70. 1000
      mobile/android/base/GoannaSmsManager.java
  71. 209
      mobile/android/base/GoannaThread.java
  72. 25
      mobile/android/base/GoannaUpdateReceiver.java
  73. 695
      mobile/android/base/GoannaView.java
  74. 81
      mobile/android/base/GoannaViewChrome.java
  75. 56
      mobile/android/base/GoannaViewContent.java
  76. 70
      mobile/android/base/GuestSession.java
  77. 76
      mobile/android/base/InputMethods.java
  78. 138
      mobile/android/base/IntentHelper.java
  79. 196
      mobile/android/base/JavaAddonManager.java
  80. 11
      mobile/android/base/LayoutInterceptor.java
  81. 42
      mobile/android/base/LocaleManager.java
  82. 116
      mobile/android/base/Locales.java
  83. 484
      mobile/android/base/Makefile.in
  84. 120
      mobile/android/base/MediaCastingBar.java
  85. 224
      mobile/android/base/MediaPlayerManager.java
  86. 254
      mobile/android/base/MemoryMonitor.java
  87. 13
      mobile/android/base/MotionEventInterceptor.java
  88. 55
      mobile/android/base/NSSBridge.java
  89. 17
      mobile/android/base/NewTabletUI.java
  90. 212
      mobile/android/base/NotificationClient.java
  91. 194
      mobile/android/base/NotificationHandler.java
  92. 377
      mobile/android/base/NotificationHelper.java
  93. 51
      mobile/android/base/NotificationService.java
  94. 129
      mobile/android/base/OrderedBroadcastHelper.java
  95. 254
      mobile/android/base/OuterLayout.java
  96. 196
      mobile/android/base/PrefsHelper.java
  97. 29
      mobile/android/base/PrivateTab.java
  98. 48
      mobile/android/base/ReaderModeUtils.java
  99. 303
      mobile/android/base/ReadingListHelper.java
  100. 126
      mobile/android/base/RemoteClientsDialogFragment.java
  101. Some files were not shown because too many files have changed in this diff Show More

1
build/mach_bootstrap.py

@ -95,7 +95,6 @@ MACH_MODULES = [
'tools/docs/mach_commands.py',
'tools/mercurial/mach_commands.py',
'tools/mach_commands.py',
'mobile/android/mach_commands.py',
]

51
config/android-common.mk

@ -1,51 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# Ensure ANDROID_SDK is defined before including this file.
# We use common android defaults for boot class path and java version.
ifndef ANDROID_SDK
$(error ANDROID_SDK must be defined before including android-common.mk)
endif
# DEBUG_JARSIGNER always debug signs.
DEBUG_JARSIGNER=$(PYTHON) $(abspath $(topsrcdir)/mobile/android/debug_sign_tool.py) \
--keytool=$(KEYTOOL) \
--jarsigner=$(JARSIGNER) \
$(NULL)
# RELEASE_JARSIGNER release signs if possible.
ifdef MOZ_SIGN_CMD
RELEASE_JARSIGNER := $(MOZ_SIGN_CMD) -f jar
else
RELEASE_JARSIGNER := $(DEBUG_JARSIGNER)
endif
# $(1) is the full path to input: foo-debug-unsigned-unaligned.apk.
# $(2) is the full path to output: foo.apk.
# Use this like: $(call RELEASE_SIGN_ANDROID_APK,foo-debug-unsigned-unaligned.apk,foo.apk)
RELEASE_SIGN_ANDROID_APK = \
cp $(1) $(2)-unaligned.apk && \
$(RELEASE_JARSIGNER) $(2)-unaligned.apk && \
$(ZIPALIGN) -f -v 4 $(2)-unaligned.apk $(2) && \
$(RM) $(2)-unaligned.apk
# For Android, this defaults to $(ANDROID_SDK)/android.jar
ifndef JAVA_BOOTCLASSPATH
JAVA_BOOTCLASSPATH = $(ANDROID_SDK)/android.jar
endif
# For Android, we default to 1.7
ifndef JAVA_VERSION
JAVA_VERSION = 1.7
endif
JAVAC_FLAGS = \
-target $(JAVA_VERSION) \
-source $(JAVA_VERSION) \
$(if $(JAVA_CLASSPATH),-classpath $(JAVA_CLASSPATH),) \
-bootclasspath $(JAVA_BOOTCLASSPATH) \
-encoding UTF8 \
-g:source,lines \
-Werror \
$(NULL)

47
configure.in

@ -4053,30 +4053,6 @@ fi
AC_SUBST(MOZ_BING_API_CLIENTID)
AC_SUBST(MOZ_BING_API_KEY)
# Whether to include optional-but-large font files in the final APK.
# We want this in mobile/android/confvars.sh, so it goes early.
MOZ_ARG_DISABLE_BOOL(android-include-fonts,
[ --disable-android-include-fonts
Disable the inclusion of fonts into the final APK],
MOZ_ANDROID_EXCLUDE_FONTS=1)
if test -n "$MOZ_ANDROID_EXCLUDE_FONTS"; then
AC_DEFINE(MOZ_ANDROID_EXCLUDE_FONTS)
fi
AC_SUBST(MOZ_ANDROID_EXCLUDE_FONTS)
# Whether this APK is destined for resource constrained devices.
# We want this in mobile/android/confvars.sh, so it goes early.
MOZ_ARG_ENABLE_BOOL(android-resource-constrained,
[ --enable-android-resource-constrained
Exclude hi-res images and similar from the final APK],
MOZ_ANDROID_RESOURCE_CONSTRAINED=1)
if test -n "$MOZ_ANDROID_RESOURCE_CONSTRAINED"; then
AC_DEFINE(MOZ_ANDROID_RESOURCE_CONSTRAINED)
fi
AC_SUBST(MOZ_ANDROID_RESOURCE_CONSTRAINED)
# Allow the application to influence configure with a confvars.sh script.
AC_MSG_CHECKING([if app-specific confvars.sh exists])
if test -f "${srcdir}/${MOZ_BUILD_APP}/confvars.sh" ; then
@ -4165,28 +4141,6 @@ WINNT|Darwin|Android)
;;
esac
dnl ========================================================
dnl Check Android SDK version depending on mobile target.
dnl ========================================================
if test -z "$gonkdir" ; then
# Minimum Android SDK API Level we require.
case "$MOZ_BUILD_APP" in
mobile/android)
android_min_api_level=20
case "$target" in
*-android*|*-linuxandroid*)
:
;;
*)
AC_MSG_ERROR([You must specify --target=arm-linux-androideabi (or some other valid android target) when building with --enable-application=mobile/android. See https://wiki.mozilla.org/Mobile/Fennec/Android#Setup_Fennec_mozconfig for more information about the necessary options])
;;
esac
;;
esac
MOZ_ANDROID_SDK($android_min_api_level)
fi
dnl ========================================================
dnl =
@ -4217,7 +4171,6 @@ MOZ_ARG_HEADER(Toolkit Options)
-o "$_DEFAULT_TOOLKIT" = "cairo-qt" \
-o "$_DEFAULT_TOOLKIT" = "cairo-cocoa" \
-o "$_DEFAULT_TOOLKIT" = "cairo-uikit" \
-o "$_DEFAULT_TOOLKIT" = "cairo-android" \
-o "$_DEFAULT_TOOLKIT" = "cairo-gonk"
then
dnl nglayout only supports building with one toolkit,

988
embedding/android/GoannaSmsManager.java

@ -1,988 +0,0 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.goanna;
import java.util.ArrayList;
import java.util.Iterator;
import android.util.Log;
import android.app.PendingIntent;
import android.app.Activity;
import android.database.Cursor;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.ContentUris;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.telephony.SmsManager;
import android.telephony.SmsMessage;
import static android.telephony.SmsMessage.MessageClass;
/**
* This class is returning unique ids for PendingIntent requestCode attribute.
* There are only |Integer.MAX_VALUE - Integer.MIN_VALUE| unique IDs available,
* and they wrap around.
*/
class PendingIntentUID
{
static private int sUID = Integer.MIN_VALUE;
static public int generate() { return sUID++; }
}
/**
* The envelope class contains all information that are needed to keep track of
* a sent SMS.
*/
class Envelope
{
enum SubParts {
SENT_PART,
DELIVERED_PART
}
protected int mId;
protected int mMessageId;
protected long mMessageTimestamp;
/**
* Number of sent/delivered remaining parts.
* @note The array has much slots as SubParts items.
*/
protected int[] mRemainingParts;
/**
* Whether sending/delivering is currently failing.
* @note The array has much slots as SubParts items.
*/
protected boolean[] mFailing;
/**
* Error type (only for sent).
*/
protected int mError;
public Envelope(int aId, int aParts) {
mId = aId;
mMessageId = -1;
mMessageTimestamp = 0;
mError = GoannaSmsManager.kNoError;
int size = Envelope.SubParts.values().length;
mRemainingParts = new int[size];
mFailing = new boolean[size];
for (int i=0; i<size; ++i) {
mRemainingParts[i] = aParts;
mFailing[i] = false;
}
}
public void decreaseRemainingParts(Envelope.SubParts aType) {
--mRemainingParts[aType.ordinal()];
if (mRemainingParts[SubParts.SENT_PART.ordinal()] >
mRemainingParts[SubParts.DELIVERED_PART.ordinal()]) {
Log.e("GoannaSmsManager", "Delivered more parts than we sent!?");
}
}
public boolean arePartsRemaining(Envelope.SubParts aType) {
return mRemainingParts[aType.ordinal()] != 0;
}
public void markAsFailed(Envelope.SubParts aType) {
mFailing[aType.ordinal()] = true;
}
public boolean isFailing(Envelope.SubParts aType) {
return mFailing[aType.ordinal()];
}
public int getMessageId() {
return mMessageId;
}
public void setMessageId(int aMessageId) {
mMessageId = aMessageId;
}
public long getMessageTimestamp() {
return mMessageTimestamp;
}
public void setMessageTimestamp(long aMessageTimestamp) {
mMessageTimestamp = aMessageTimestamp;
}
public int getError() {
return mError;
}
public void setError(int aError) {
mError = aError;
}
}
/**
* Postman class is a singleton that manages Envelope instances.
*/
class Postman
{
public static final int kUnknownEnvelopeId = -1;
private static final Postman sInstance = new Postman();
private ArrayList<Envelope> mEnvelopes = new ArrayList<Envelope>(1);
private Postman() {}
public static Postman getInstance() {
return sInstance;
}
public int createEnvelope(int aParts) {
/*
* We are going to create the envelope in the first empty slot in the array
* list. If there is no empty slot, we create a new one.
*/
int size = mEnvelopes.size();
for (int i=0; i<size; ++i) {
if (mEnvelopes.get(i) == null) {
mEnvelopes.set(i, new Envelope(i, aParts));
return i;
}
}
mEnvelopes.add(new Envelope(size, aParts));
return size;
}
public Envelope getEnvelope(int aId) {
if (aId < 0 || mEnvelopes.size() <= aId) {
Log.e("GoannaSmsManager", "Trying to get an unknown Envelope!");
return null;
}
Envelope envelope = mEnvelopes.get(aId);
if (envelope == null) {
Log.e("GoannaSmsManager", "Trying to get an empty Envelope!");
}
return envelope;
}
public void destroyEnvelope(int aId) {
if (aId < 0 || mEnvelopes.size() <= aId) {
Log.e("GoannaSmsManager", "Trying to destroy an unknown Envelope!");
return;
}
if (mEnvelopes.set(aId, null) == null) {
Log.e("GoannaSmsManager", "Trying to destroy an empty Envelope!");
}
}
}
class SmsIOThread extends Thread {
private final static SmsIOThread sInstance = new SmsIOThread();
private Handler mHandler;
public static SmsIOThread getInstance() {
return sInstance;
}
public boolean execute(Runnable r) {
return mHandler.post(r);
}
public void run() {
Looper.prepare();
mHandler = new Handler();
Looper.loop();
}
}
class MessagesListManager
{
private static final MessagesListManager sInstance = new MessagesListManager();
public static MessagesListManager getInstance() {
return sInstance;
}
private ArrayList<Cursor> mCursors = new ArrayList<Cursor>(0);
public int add(Cursor aCursor) {
int size = mCursors.size();
for (int i=0; i<size; ++i) {
if (mCursors.get(i) == null) {
mCursors.set(i, aCursor);
return i;
}
}
mCursors.add(aCursor);
return size;
}
public Cursor get(int aId) {
if (aId < 0 || mCursors.size() <= aId) {
Log.e("GoannaSmsManager", "Trying to get an unknown list!");
return null;
}
Cursor cursor = mCursors.get(aId);
if (cursor == null) {
Log.e("GoannaSmsManager", "Trying to get an empty list!");
}
return cursor;
}
public void remove(int aId) {
if (aId < 0 || mCursors.size() <= aId) {
Log.e("GoannaSmsManager", "Trying to destroy an unknown list!");
return;
}
Cursor cursor = mCursors.set(aId, null);
if (cursor == null) {
Log.e("GoannaSmsManager", "Trying to destroy an empty list!");
return;
}
cursor.close();
}
public void clear() {
for (int i=0; i<mCursors.size(); ++i) {
Cursor c = mCursors.get(i);
if (c != null) {
c.close();
}
}
mCursors.clear();
}
}
public class GoannaSmsManager
extends BroadcastReceiver
implements ISmsManager
{
public final static String ACTION_SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
public final static String ACTION_SMS_SENT = "org.mozilla.goanna.SMS_SENT";
public final static String ACTION_SMS_DELIVERED = "org.mozilla.goanna.SMS_DELIVERED";
/*
* Make sure that the following error codes are in sync with the ones
* defined in dom/mobilemessage/interfaces/nsIMobileMessageCallback.idl. They are owned
* owned by the interface.
*/
public final static int kNoError = 0;
public final static int kNoSignalError = 1;
public final static int kNotFoundError = 2;
public final static int kUnknownError = 3;
public final static int kInternalError = 4;
public final static int kNoSimCardError = 5;
public final static int kRadioDisabledError = 6;
public final static int kInvalidAddressError = 7;
public final static int kFdnCheckError = 8;
public final static int kNonActiveSimCardError = 9;
public final static int kStorageFullError = 10;
public final static int kSimNotMatchedError = 11;
private final static int kMaxMessageSize = 160;
private final static Uri kSmsContentUri = Uri.parse("content://sms");
private final static Uri kSmsSentContentUri = Uri.parse("content://sms/sent");
private final static int kSmsTypeInbox = 1;
private final static int kSmsTypeSentbox = 2;
/*
* Keep the following state codes in syng with |DeliveryState| in:
* dom/mobilemessage/Types.h
*/
private final static int kDeliveryStateSent = 0;
private final static int kDeliveryStateReceived = 1;
private final static int kDeliveryStateSending = 2;
private final static int kDeliveryStateError = 3;
private final static int kDeliveryStateUnknown = 4;
private final static int kDeliveryStateNotDownloaded = 5;
private final static int kDeliveryStateEndGuard = 6;
/*
* Keep the following status codes in sync with |DeliveryStatus| in:
* dom/mobilemessage/Types.h
*/
private final static int kDeliveryStatusNotApplicable = 0;
private final static int kDeliveryStatusSuccess = 1;
private final static int kDeliveryStatusPending = 2;
private final static int kDeliveryStatusError = 3;
/*
* android.provider.Telephony.Sms.STATUS_*. Duplicated because they're not
* part of Android public API.
*/
private final static int kInternalDeliveryStatusNone = -1;
private final static int kInternalDeliveryStatusComplete = 0;
private final static int kInternalDeliveryStatusPending = 32;
private final static int kInternalDeliveryStatusFailed = 64;
/*
* Keep the following values in sync with |MessageClass| in:
* dom/mobilemessage/Types.h
*/
private final static int kMessageClassNormal = 0;
private final static int kMessageClassClass0 = 1;
private final static int kMessageClassClass1 = 2;
private final static int kMessageClassClass2 = 3;
private final static int kMessageClassClass3 = 4;
private final static String[] kRequiredMessageRows = new String[] { "_id", "address", "body", "date", "type", "status" };
public GoannaSmsManager() {
SmsIOThread.getInstance().start();
}
public void start() {
IntentFilter smsFilter = new IntentFilter();
smsFilter.addAction(GoannaSmsManager.ACTION_SMS_RECEIVED);
smsFilter.addAction(GoannaSmsManager.ACTION_SMS_SENT);
smsFilter.addAction(GoannaSmsManager.ACTION_SMS_DELIVERED);
GoannaApp.mAppContext.registerReceiver(this, smsFilter);
}
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_SMS_RECEIVED)) {
// TODO: Try to find the receiver number to be able to populate
// SmsMessage.receiver.
// TODO: Get the id and the date from the stock app saved message.
// Using the stock app saved message require us to wait for it to
// be saved which can lead to race conditions.
Bundle bundle = intent.getExtras();
if (bundle == null) {
return;
}
Object[] pdus = (Object[]) bundle.get("pdus");
for (int i=0; i<pdus.length; ++i) {
SmsMessage msg = SmsMessage.createFromPdu((byte[])pdus[i]);
GoannaAppShell.notifySmsReceived(msg.getDisplayOriginatingAddress(),
msg.getDisplayMessageBody(),
getGoannaMessageClass(msg.getMessageClass()),
System.currentTimeMillis());
}
return;
}
if (intent.getAction().equals(ACTION_SMS_SENT) ||
intent.getAction().equals(ACTION_SMS_DELIVERED)) {
Bundle bundle = intent.getExtras();
if (bundle == null || !bundle.containsKey("envelopeId") ||
!bundle.containsKey("number") || !bundle.containsKey("message") ||
!bundle.containsKey("requestId")) {
Log.e("GoannaSmsManager", "Got an invalid ACTION_SMS_SENT/ACTION_SMS_DELIVERED!");
return;
}
int envelopeId = bundle.getInt("envelopeId");
Postman postman = Postman.getInstance();
Envelope envelope = postman.getEnvelope(envelopeId);
if (envelope == null) {
Log.e("GoannaSmsManager", "Got an invalid envelope id (or Envelope has been destroyed)!");
return;
}
Envelope.SubParts part = intent.getAction().equals(ACTION_SMS_SENT)
? Envelope.SubParts.SENT_PART
: Envelope.SubParts.DELIVERED_PART;
envelope.decreaseRemainingParts(part);
if (getResultCode() != Activity.RESULT_OK) {
switch (getResultCode()) {
case SmsManager.RESULT_ERROR_NULL_PDU:
envelope.setError(kInternalError);
break;
case SmsManager.RESULT_ERROR_NO_SERVICE:
case SmsManager.RESULT_ERROR_RADIO_OFF:
envelope.setError(kNoSignalError);
break;
case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
default:
envelope.setError(kUnknownError);
break;
}
envelope.markAsFailed(part);
Log.i("GoannaSmsManager", "SMS part sending failed!");
}
if (envelope.arePartsRemaining(part)) {
return;
}
if (envelope.isFailing(part)) {
if (part == Envelope.SubParts.SENT_PART) {
GoannaAppShell.notifySmsSendFailed(envelope.getError(),
bundle.getInt("requestId"));
Log.i("GoannaSmsManager", "SMS sending failed!");
} else {
GoannaAppShell.notifySmsDelivery(envelope.getMessageId(),
kDeliveryStatusError,
bundle.getString("number"),
bundle.getString("message"),
envelope.getMessageTimestamp());
Log.i("GoannaSmsManager", "SMS delivery failed!");
}
} else {
if (part == Envelope.SubParts.SENT_PART) {
String number = bundle.getString("number");
String message = bundle.getString("message");
long timestamp = System.currentTimeMillis();
int id = saveSentMessage(number, message, timestamp);
GoannaAppShell.notifySmsSent(id, number, message, timestamp,
bundle.getInt("requestId"));
envelope.setMessageId(id);
envelope.setMessageTimestamp(timestamp);
Log.i("GoannaSmsManager", "SMS sending was successfull!");
} else {
GoannaAppShell.notifySmsDelivery(envelope.getMessageId(),
kDeliveryStatusSuccess,
bundle.getString("number"),
bundle.getString("message"),
envelope.getMessageTimestamp());
Log.i("GoannaSmsManager", "SMS succesfully delivered!");
}
}
// Destroy the envelope object only if the SMS has been sent and delivered.
if (!envelope.arePartsRemaining(Envelope.SubParts.SENT_PART) &&
!envelope.arePartsRemaining(Envelope.SubParts.DELIVERED_PART)) {
postman.destroyEnvelope(envelopeId);
}
return;
}
}
public void send(String aNumber, String aMessage, int aRequestId) {
int envelopeId = Postman.kUnknownEnvelopeId;
try {
SmsManager sm = SmsManager.getDefault();
Intent sentIntent = new Intent(ACTION_SMS_SENT);
Intent deliveredIntent = new Intent(ACTION_SMS_DELIVERED);
Bundle bundle = new Bundle();
bundle.putString("number", aNumber);
bundle.putString("message", aMessage);
bundle.putInt("requestId", aRequestId);
if (aMessage.length() <= kMaxMessageSize) {
envelopeId = Postman.getInstance().createEnvelope(1);
bundle.putInt("envelopeId", envelopeId);
sentIntent.putExtras(bundle);
deliveredIntent.putExtras(bundle);
/*
* There are a few things to know about getBroadcast and pending intents:
* - the pending intents are in a shared pool maintained by the system;
* - each pending intent is identified by a token;
* - when a new pending intent is created, if it has the same token as
* another intent in the pool, one of them has to be removed.
*
* To prevent having a hard time because of this situation, we give a
* unique id to all pending intents we are creating. This unique id is
* generated by GetPendingIntentUID().
*/
PendingIntent sentPendingIntent =
PendingIntent.getBroadcast(GoannaApp.mAppContext,
PendingIntentUID.generate(), sentIntent,
PendingIntent.FLAG_CANCEL_CURRENT);
PendingIntent deliveredPendingIntent =
PendingIntent.getBroadcast(GoannaApp.mAppContext,
PendingIntentUID.generate(), deliveredIntent,
PendingIntent.FLAG_CANCEL_CURRENT);
sm.sendTextMessage(aNumber, "", aMessage,
sentPendingIntent, deliveredPendingIntent);
} else {
ArrayList<String> parts = sm.divideMessage(aMessage);
envelopeId = Postman.getInstance().createEnvelope(parts.size());
bundle.putInt("envelopeId", envelopeId);
sentIntent.putExtras(bundle);
deliveredIntent.putExtras(bundle);
ArrayList<PendingIntent> sentPendingIntents =
new ArrayList<PendingIntent>(parts.size());
ArrayList<PendingIntent> deliveredPendingIntents =
new ArrayList<PendingIntent>(parts.size());
for (int i=0; i<parts.size(); ++i) {
sentPendingIntents.add(
PendingIntent.getBroadcast(GoannaApp.mAppContext,
PendingIntentUID.generate(), sentIntent,
PendingIntent.FLAG_CANCEL_CURRENT)
);
deliveredPendingIntents.add(
PendingIntent.getBroadcast(GoannaApp.mAppContext,
PendingIntentUID.generate(), deliveredIntent,
PendingIntent.FLAG_CANCEL_CURRENT)
);
}
sm.sendMultipartTextMessage(aNumber, "", parts, sentPendingIntents,
deliveredPendingIntents);
}
} catch (Exception e) {
Log.e("GoannaSmsManager", "Failed to send an SMS: ", e);
if (envelopeId != Postman.kUnknownEnvelopeId) {
Postman.getInstance().destroyEnvelope(envelopeId);
}
GoannaAppShell.notifySmsSendFailed(kUnknownError, aRequestId);
}
}
public int saveSentMessage(String aRecipient, String aBody, long aDate) {
try {
ContentValues values = new ContentValues();
values.put("address", aRecipient);
values.put("body", aBody);
values.put("date", aDate);
// Always 'PENDING' because we always request status report.
values.put("status", kInternalDeliveryStatusPending);
ContentResolver cr = GoannaApp.mAppContext.getContentResolver();
Uri uri = cr.insert(kSmsSentContentUri, values);
long id = ContentUris.parseId(uri);
// The DOM API takes a 32bits unsigned int for the id. It's unlikely that
// we happen to need more than that but it doesn't cost to check.
if (id > Integer.MAX_VALUE) {
throw new IdTooHighException();
}
return (int)id;
} catch (IdTooHighException e) {
Log.e("GoannaSmsManager", "The id we received is higher than the higher allowed value.");
return -1;
} catch (Exception e) {
Log.e("GoannaSmsManager", "Something went wrong when trying to write a sent message: " + e);
return -1;
}
}
public void getMessage(int aMessageId, int aRequestId) {
class GetMessageRunnable implements Runnable {
private int mMessageId;
private int mRequestId;
GetMessageRunnable(int aMessageId, int aRequestId) {
mMessageId = aMessageId;
mRequestId = aRequestId;
}
@Override
public void run() {
Cursor cursor = null;
try {
ContentResolver cr = GoannaApp.mAppContext.getContentResolver();
Uri message = ContentUris.withAppendedId(kSmsContentUri, mMessageId);
cursor = cr.query(message, kRequiredMessageRows, null, null, null);
if (cursor == null || cursor.getCount() == 0) {
throw new NotFoundException();
}
if (cursor.getCount() != 1) {
throw new TooManyResultsException();
}
cursor.moveToFirst();
if (cursor.getInt(cursor.getColumnIndex("_id")) != mMessageId) {
throw new UnmatchingIdException();
}
int type = cursor.getInt(cursor.getColumnIndex("type"));
int deliveryStatus;
String sender = "";
String receiver = "";
if (type == kSmsTypeInbox) {
deliveryStatus = kDeliveryStatusSuccess;
sender = cursor.getString(cursor.getColumnIndex("address"));
} else if (type == kSmsTypeSentbox) {
deliveryStatus = getGoannaDeliveryStatus(cursor.getInt(cursor.getColumnIndex("status")));
receiver = cursor.getString(cursor.getColumnIndex("address"));
} else {
throw new InvalidTypeException();
}
GoannaAppShell.notifyGetSms(cursor.getInt(cursor.getColumnIndex("_id")),
deliveryStatus,
receiver, sender,
cursor.getString(cursor.getColumnIndex("body")),
cursor.getLong(cursor.getColumnIndex("date")),
mRequestId);
} catch (NotFoundException e) {
Log.i("GoannaSmsManager", "Message id " + mMessageId + " not found");
GoannaAppShell.notifyGetSmsFailed(kNotFoundError, mRequestId);
} catch (UnmatchingIdException e) {
Log.e("GoannaSmsManager", "Requested message id (" + mMessageId +
") is different from the one we got.");
GoannaAppShell.notifyGetSmsFailed(kUnknownError, mRequestId);
} catch (TooManyResultsException e) {
Log.e("GoannaSmsManager", "Get too many results for id " + mMessageId);
GoannaAppShell.notifyGetSmsFailed(kUnknownError, mRequestId);
} catch (InvalidTypeException e) {
Log.i("GoannaSmsManager", "Message has an invalid type, we ignore it.");
GoannaAppShell.notifyGetSmsFailed(kNotFoundError, mRequestId);
} catch (Exception e) {
Log.e("GoannaSmsManager", "Error while trying to get message: " + e);
GoannaAppShell.notifyGetSmsFailed(kUnknownError, mRequestId);
} finally {
if (cursor != null) {
cursor.close();
}
}
}
}
if (!SmsIOThread.getInstance().execute(new GetMessageRunnable(aMessageId, aRequestId))) {
Log.e("GoannaSmsManager", "Failed to add GetMessageRunnable to the SmsIOThread");
GoannaAppShell.notifyGetSmsFailed(kUnknownError, aRequestId);
}
}
public void deleteMessage(int aMessageId, int aRequestId) {
class DeleteMessageRunnable implements Runnable {
private int mMessageId;
private int mRequestId;
DeleteMessageRunnable(int aMessageId, int aRequestId) {
mMessageId = aMessageId;
mRequestId = aRequestId;
}
@Override
public void run() {
try {
ContentResolver cr = GoannaApp.mAppContext.getContentResolver();
Uri message = ContentUris.withAppendedId(kSmsContentUri, mMessageId);
int count = cr.delete(message, null, null);
if (count > 1) {
throw new TooManyResultsException();
}
GoannaAppShell.notifySmsDeleted(count == 1, mRequestId);
} catch (TooManyResultsException e) {
Log.e("GoannaSmsManager", "Delete more than one message? " + e);
GoannaAppShell.notifySmsDeleteFailed(kUnknownError, mRequestId);
} catch (Exception e) {
Log.e("GoannaSmsManager", "Error while trying to delete a message: " + e);
GoannaAppShell.notifySmsDeleteFailed(kUnknownError, mRequestId);
}
}
}
if (!SmsIOThread.getInstance().execute(new DeleteMessageRunnable(aMessageId, aRequestId))) {
Log.e("GoannaSmsManager", "Failed to add GetMessageRunnable to the SmsIOThread");
GoannaAppShell.notifySmsDeleteFailed(kUnknownError, aRequestId);
}
}
public void createMessageList(long aStartDate, long aEndDate, String[] aNumbers, int aNumbersCount, int aDeliveryState, boolean aReverse, int aRequestId) {
class CreateMessageListRunnable implements Runnable {
private long mStartDate;
private long mEndDate;
private String[] mNumbers;
private int mNumbersCount;
private int mDeliveryState;
private boolean mReverse;
private int mRequestId;
CreateMessageListRunnable(long aStartDate, long aEndDate, String[] aNumbers, int aNumbersCount, int aDeliveryState, boolean aReverse, int aRequestId) {
mStartDate = aStartDate;
mEndDate = aEndDate;
mNumbers = aNumbers;
mNumbersCount = aNumbersCount;
mDeliveryState = aDeliveryState;
mReverse = aReverse;
mRequestId = aRequestId;
}
@Override
public void run() {
Cursor cursor = null;
boolean closeCursor = true;
try {
// TODO: should use the |selectionArgs| argument in |ContentResolver.query()|.
ArrayList<String> restrictions = new ArrayList<String>();
if (mStartDate != 0) {
restrictions.add("date >= " + mStartDate);
}
if (mEndDate != 0) {
restrictions.add("date <= " + mEndDate);
}
if (mNumbersCount > 0) {
String numberRestriction = "address IN ('" + mNumbers[0] + "'";
for (int i=1; i<mNumbersCount; ++i) {
numberRestriction += ", '" + mNumbers[i] + "'";
}
numberRestriction += ")";
restrictions.add(numberRestriction);
}
if (mDeliveryState == kDeliveryStateUnknown) {
restrictions.add("type IN ('" + kSmsTypeSentbox + "', '" + kSmsTypeInbox + "')");
} else if (mDeliveryState == kDeliveryStateSent) {
restrictions.add("type = " + kSmsTypeSentbox);
} else if (mDeliveryState == kDeliveryStateReceived) {
restrictions.add("type = " + kSmsTypeInbox);
} else {
throw new UnexpectedDeliveryStateException();
}
String restrictionText = restrictions.size() > 0 ? restrictions.get(0) : "";
for (int i=1; i<restrictions.size(); ++i) {
restrictionText += " AND " + restrictions.get(i);
}
ContentResolver cr = GoannaApp.mAppContext.getContentResolver();
cursor = cr.query(kSmsContentUri, kRequiredMessageRows, restrictionText, null,
mReverse ? "date DESC" : "date ASC");
if (cursor.getCount() == 0) {
GoannaAppShell.notifyNoMessageInList(mRequestId);
return;
}
cursor.moveToFirst();
int type = cursor.getInt(cursor.getColumnIndex("type"));
int deliveryStatus;
String sender = "";
String receiver = "";
if (type == kSmsTypeInbox) {
deliveryStatus = kDeliveryStatusSuccess;
sender = cursor.getString(cursor.getColumnIndex("address"));
} else if (type == kSmsTypeSentbox) {
deliveryStatus = getGoannaDeliveryStatus(cursor.getInt(cursor.getColumnIndex("status")));
receiver = cursor.getString(cursor.getColumnIndex("address"));
} else {
throw new UnexpectedDeliveryStateException();
}
int listId = MessagesListManager.getInstance().add(cursor);
closeCursor = false;
GoannaAppShell.notifyListCreated(listId,
cursor.getInt(cursor.getColumnIndex("_id")),
deliveryStatus,
receiver, sender,
cursor.getString(cursor.getColumnIndex("body")),
cursor.getLong(cursor.getColumnIndex("date")),
mRequestId);
} catch (UnexpectedDeliveryStateException e) {
Log.e("GoannaSmsManager", "Unexcepted delivery state type: " + e);
GoannaAppShell.notifyReadingMessageListFailed(kUnknownError, mRequestId);
} catch (Exception e) {
Log.e("GoannaSmsManager", "Error while trying to create a message list cursor: " + e);
GoannaAppShell.notifyReadingMessageListFailed(kUnknownError, mRequestId);
} finally {
// Close the cursor if MessagesListManager isn't taking care of it.
// We could also just check if it is in the MessagesListManager list but
// that would be less efficient.
if (cursor != null && closeCursor) {
cursor.close();
}
}
}
}
if (!SmsIOThread.getInstance().execute(new CreateMessageListRunnable(aStartDate, aEndDate, aNumbers, aNumbersCount, aDeliveryState, aReverse, aRequestId))) {
Log.e("GoannaSmsManager", "Failed to add CreateMessageListRunnable to the SmsIOThread");
GoannaAppShell.notifyReadingMessageListFailed(kUnknownError, aRequestId);
}
}
public void getNextMessageInList(int aListId, int aRequestId) {
class GetNextMessageInListRunnable implements Runnable {
private int mListId;
private int mRequestId;
GetNextMessageInListRunnable(int aListId, int aRequestId) {
mListId = aListId;
mRequestId = aRequestId;
}
@Override
public void run() {
try {
Cursor cursor = MessagesListManager.getInstance().get(mListId);
if (!cursor.moveToNext()) {
MessagesListManager.getInstance().remove(mListId);
GoannaAppShell.notifyNoMessageInList(mRequestId);
return;
}
int type = cursor.getInt(cursor.getColumnIndex("type"));
int deliveryStatus;
String sender = "";
String receiver = "";
if (type == kSmsTypeInbox) {
deliveryStatus = kDeliveryStatusSuccess;
sender = cursor.getString(cursor.getColumnIndex("address"));
} else if (type == kSmsTypeSentbox) {
deliveryStatus = getGoannaDeliveryStatus(cursor.getInt(cursor.getColumnIndex("status")));
receiver = cursor.getString(cursor.getColumnIndex("address"));
} else {
throw new UnexpectedDeliveryStateException();
}
int listId = MessagesListManager.getInstance().add(cursor);
GoannaAppShell.notifyGotNextMessage(cursor.getInt(cursor.getColumnIndex("_id")),
deliveryStatus,
receiver, sender,
cursor.getString(cursor.getColumnIndex("body")),
cursor.getLong(cursor.getColumnIndex("date")),
mRequestId);
} catch (UnexpectedDeliveryStateException e) {
Log.e("GoannaSmsManager", "Unexcepted delivery state type: " + e);
GoannaAppShell.notifyReadingMessageListFailed(kUnknownError, mRequestId);
} catch (Exception e) {
Log.e("GoannaSmsManager", "Error while trying to get the next message of a list: " + e);
GoannaAppShell.notifyReadingMessageListFailed(kUnknownError, mRequestId);
}
}
}
if (!SmsIOThread.getInstance().execute(new GetNextMessageInListRunnable(aListId, aRequestId))) {
Log.e("GoannaSmsManager", "Failed to add GetNextMessageInListRunnable to the SmsIOThread");
GoannaAppShell.notifyReadingMessageListFailed(kUnknownError, aRequestId);
}
}
public void clearMessageList(int aListId) {
MessagesListManager.getInstance().remove(aListId);
}
public void stop() {
GoannaApp.mAppContext.unregisterReceiver(this);
}
public void shutdown() {
SmsIOThread.getInstance().interrupt();
MessagesListManager.getInstance().clear();
}
private int getGoannaDeliveryStatus(int aDeliveryStatus) {
if (aDeliveryStatus == kInternalDeliveryStatusNone) {
return kDeliveryStatusNotApplicable;
}
if (aDeliveryStatus >= kInternalDeliveryStatusFailed) {
return kDeliveryStatusError;
}
if (aDeliveryStatus >= kInternalDeliveryStatusPending) {
return kDeliveryStatusPending;
}
return kDeliveryStatusSuccess;
}
private int getGoannaMessageClass(MessageClass aMessageClass) {
switch (aMessageClass) {
case UNKNOWN:
return kMessageClassNormal;
case CLASS_0:
return kMessageClassClass0;
case CLASS_1:
return kMessageClassClass1;
case CLASS_2:
return kMessageClassClass2;
case CLASS_3:
return kMessageClassClass3;
}
}
class IdTooHighException extends Exception {
private static final long serialVersionUID = 395697882128640L;
}
class InvalidTypeException extends Exception {
private static final long serialVersionUID = 23359904803795434L;
}
class NotFoundException extends Exception {
private static final long serialVersionUID = 266226999371957426L;
}
class TooManyResultsException extends Exception {
private static final long serialVersionUID = 48899777673841920L;
}
class UnexpectedDeliveryStateException extends Exception {
private static final long serialVersionUID = 5044567998961920L;
}
class UnmatchingIdException extends Exception {
private static final long serialVersionUID = 1935649715512128L;
}
}

23
embedding/android/goannaview_example/AndroidManifest.xml.in

@ -1,23 +0,0 @@
#filter substitution
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.mozilla.goannaviewexample"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="8"
android:targetSdkVersion="@ANDROID_TARGET_SDK@"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
<application android:label="@string/app_name"
android:icon="@drawable/ic_launcher"
android:hardwareAccelerated="true">
<activity android:name="GoannaViewExample"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

14
embedding/android/goannaview_example/GoannaViewExample.java

@ -1,14 +0,0 @@
package org.mozilla.goannaviewexample;
import android.app.Activity;
import android.os.Bundle;
import android.util.AttributeSet;
public class GoannaViewExample extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}

65
embedding/android/goannaview_example/Makefile.in

@ -1,65 +0,0 @@
PP_TARGETS = properties manifest
manifest = AndroidManifest.xml.in
include $(topsrcdir)/config/rules.mk
GARBAGE = \
AndroidManifest.xml \
proguard-project.txt \
project.properties \
ant.properties \
build.xml \
local.properties \
goannaview_example.apk \
$(NULL)
GARBAGE_DIRS = \
assets \
goannaview_library \
gen \
bin \
libs \
res \
src \
binaries \
$(NULL)
ANDROID=$(ANDROID_TOOLS)/android
TARGET="android-$(ANDROID_TARGET_SDK)"
PACKAGE_DEPS = \
assets/libxul.so \
build.xml \
src/org/mozilla/goannaviewexample/GoannaViewExample.java \
$(CURDIR)/res/layout/main.xml \
$(CURDIR)/AndroidManifest.xml \
$(NULL)
$(CURDIR)/res/layout/main.xml: $(srcdir)/main.xml
$(NSINSTALL) $(srcdir)/main.xml res/layout/
src/org/mozilla/goannaviewexample/GoannaViewExample.java: $(srcdir)/GoannaViewExample.java
$(NSINSTALL) $(srcdir)/GoannaViewExample.java src/org/mozilla/goannaviewexample/
assets/libxul.so: $(DIST)/goannaview_library/goannaview_assets.zip FORCE
$(UNZIP) -o $(DIST)/goannaview_library/goannaview_assets.zip
build.xml: $(CURDIR)/AndroidManifest.xml
mv AndroidManifest.xml AndroidManifest.xml.save
$(ANDROID) create project --name GoannaViewExample --target $(TARGET) --path $(CURDIR) --activity GoannaViewExample --package org.mozilla.goannaviewexample
$(ANDROID) update project --target $(TARGET) --path $(CURDIR) --library $(DEPTH)/mobile/android/goannaview_library
$(RM) $(CURDIR)/res/layout/main.xml
$(NSINSTALL) $(srcdir)/main.xml res/layout/
$(RM) AndroidManifest.xml
mv AndroidManifest.xml.save AndroidManifest.xml
echo jar.libs.dir=libs >> project.properties
bin/GoannaViewExample-debug.apk: $(PACKAGE_DEPS)
ant debug
goannaview_example.apk: bin/GoannaViewExample-debug.apk
cp $< $@
package: goannaview_example.apk FORCE

12
embedding/android/goannaview_example/main.xml

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:goanna="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<org.mozilla.goanna.GoannaView android:id="@+id/goanna_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
goanna:url="about:mozilla"/>
</LinearLayout>

0
embedding/android/goannaview_example/moz.build

3
embedding/moz.build

@ -6,9 +6,6 @@
DIRS += ['components', 'browser']
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
DIRS += ['android/goannaview_example']
TEST_DIRS += ['test']
if CONFIG['ENABLE_TESTS']:

373
mobile/android/LICENSE

@ -1,373 +0,0 @@
Mozilla Public License Version 2.0
==================================
1. Definitions
--------------
1.1. "Contributor"
means each individual or legal entity that creates, contributes to
the creation of, or owns Covered Software.
1.2. "Contributor Version"
means the combination of the Contributions of others (if any) used
by a Contributor and that particular Contributor's Contribution.
1.3. "Contribution"
means Covered Software of a particular Contributor.
1.4. "Covered Software"
means Source Code Form to which the initial Contributor has attached
the notice in Exhibit A, the Executable Form of such Source Code
Form, and Modifications of such Source Code Form, in each case
including portions thereof.
1.5. "Incompatible With Secondary Licenses"
means
(a) that the initial Contributor has attached the notice described
in Exhibit B to the Covered Software; or
(b) that the Covered Software was made available under the terms of
version 1.1 or earlier of the License, but not also under the
terms of a Secondary License.
1.6. "Executable Form"
means any form of the work other than Source Code Form.
1.7. "Larger Work"
means a work that combines Covered Software with other material, in
a separate file or files, that is not Covered Software.
1.8. "License"
means this document.
1.9. "Licensable"
means having the right to grant, to the maximum extent possible,
whether at the time of the initial grant or subsequently, any and
all of the rights conveyed by this License.
1.10. "Modifications"
means any of the following:
(a) any file in Source Code Form that results from an addition to,
deletion from, or modification of the contents of Covered
Software; or
(b) any new file in Source Code Form that contains any Covered
Software.
1.11. "Patent Claims" of a Contributor
means any patent claim(s), including without limitation, method,
process, and apparatus claims, in any patent Licensable by such
Contributor that would be infringed, but for the grant of the
License, by the making, using, selling, offering for sale, having
made, import, or transfer of either its Contributions or its
Contributor Version.
1.12. "Secondary License"
means either the GNU General Public License, Version 2.0, the GNU
Lesser General Public License, Version 2.1, the GNU Affero General
Public License, Version 3.0, or any later versions of those
licenses.
1.13. "Source Code Form"
means the form of the work preferred for making modifications.
1.14. "You" (or "Your")
means an individual or a legal entity exercising rights under this
License. For legal entities, "You" includes any entity that
controls, is controlled by, or is under common control with You. For
purposes of this definition, "control" means (a) the power, direct
or indirect, to cause the direction or management of such entity,
whether by contract or otherwise, or (b) ownership of more than
fifty percent (50%) of the outstanding shares or beneficial
ownership of such entity.
2. License Grants and Conditions
--------------------------------
2.1. Grants
Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:
(a) under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available,