summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embedding/android/GeckoSmsManager.java983
-rw-r--r--gfx/layers/ipc/GeckoContentController.h70
-rw-r--r--ipc/glue/GeckoChildProcessHost.cpp801
-rw-r--r--ipc/glue/GeckoChildProcessHost.h171
-rw-r--r--mobile/android/base/GeckoAccessibility.java379
-rw-r--r--mobile/android/base/GeckoActivity.java100
-rw-r--r--mobile/android/base/GeckoApp.java2466
-rw-r--r--mobile/android/base/GeckoAppShell.java2500
-rw-r--r--mobile/android/base/GeckoApplication.java112
-rw-r--r--mobile/android/base/GeckoBatteryManager.java193
-rw-r--r--mobile/android/base/GeckoConnectivityReceiver.java82
-rw-r--r--mobile/android/base/GeckoEditable.java1207
-rw-r--r--mobile/android/base/GeckoEvent.java694
-rw-r--r--mobile/android/base/GeckoHalDefines.java25
-rw-r--r--mobile/android/base/GeckoInputConnection.java1032
-rw-r--r--mobile/android/base/GeckoJavaSampler.java184
-rw-r--r--mobile/android/base/GeckoMessageReceiver.java19
-rw-r--r--mobile/android/base/GeckoNetworkManager.java297
-rw-r--r--mobile/android/base/GeckoPreferenceFragment.java45
-rw-r--r--mobile/android/base/GeckoPreferences.java729
-rw-r--r--mobile/android/base/GeckoProfile.java399
-rw-r--r--mobile/android/base/GeckoScreenOrientationListener.java215
-rw-r--r--mobile/android/base/GeckoSmsManager.java996
-rw-r--r--mobile/android/base/GeckoThread.java149
-rw-r--r--mobile/android/base/GeckoUpdateReceiver.java25
-rw-r--r--mobile/android/base/GeckoView.java96
-rw-r--r--mobile/android/base/GeckoView.java.frag126
-rw-r--r--mobile/android/base/GeckoViewsFactory.java133
-rw-r--r--mobile/android/base/gfx/GeckoLayerClient.java978
-rw-r--r--mobile/android/base/menu/GeckoMenu.java629
-rw-r--r--mobile/android/base/menu/GeckoMenuInflater.java158
-rw-r--r--mobile/android/base/menu/GeckoMenuItem.java357
-rw-r--r--mobile/android/base/menu/GeckoSubMenu.java81
-rw-r--r--mobile/android/base/mozglue/GeckoLoader.java.in284
-rw-r--r--mobile/android/base/resources/layout/gecko_app.xml64
-rw-r--r--mobile/android/base/util/GeckoBackgroundThread.java55
-rw-r--r--mobile/android/base/util/GeckoEventListener.java15
-rw-r--r--mobile/android/base/util/GeckoEventResponder.java16
-rw-r--r--mobile/android/base/util/GeckoJarReader.java171
-rw-r--r--mobile/android/base/widget/GeckoActionProvider.java140
-rw-r--r--mobile/android/base/widget/GeckoPopupMenu.java172
-rw-r--r--mozglue/android/nsGeckoUtils.cpp126
-rw-r--r--tools/profiler/GeckoProfiler.h166
-rw-r--r--tools/profiler/GeckoProfilerFunc.h71
-rw-r--r--tools/profiler/GeckoProfilerImpl.h350
45 files changed, 0 insertions, 18061 deletions
diff --git a/embedding/android/GeckoSmsManager.java b/embedding/android/GeckoSmsManager.java
deleted file mode 100644
index c22a89ea0..000000000
--- a/embedding/android/GeckoSmsManager.java
+++ /dev/null
@@ -1,983 +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.gecko;
-
-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 = GeckoSmsManager.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("GeckoSmsManager", "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("GeckoSmsManager", "Trying to get an unknown Envelope!");
- return null;
- }
-
- Envelope envelope = mEnvelopes.get(aId);
- if (envelope == null) {
- Log.e("GeckoSmsManager", "Trying to get an empty Envelope!");
- }
-
- return envelope;
- }
-
- public void destroyEnvelope(int aId) {
- if (aId < 0 || mEnvelopes.size() <= aId) {
- Log.e("GeckoSmsManager", "Trying to destroy an unknown Envelope!");
- return;
- }
-
- if (mEnvelopes.set(aId, null) == null) {
- Log.e("GeckoSmsManager", "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("GeckoSmsManager", "Trying to get an unknown list!");
- return null;
- }
-
- Cursor cursor = mCursors.get(aId);
- if (cursor == null) {
- Log.e("GeckoSmsManager", "Trying to get an empty list!");
- }
-
- return cursor;
- }
-
- public void remove(int aId) {
- if (aId < 0 || mCursors.size() <= aId) {
- Log.e("GeckoSmsManager", "Trying to destroy an unknown list!");
- return;
- }
-
- Cursor cursor = mCursors.set(aId, null);
- if (cursor == null) {
- Log.e("GeckoSmsManager", "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 GeckoSmsManager
- 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.gecko.SMS_SENT";
- public final static String ACTION_SMS_DELIVERED = "org.mozilla.gecko.SMS_DELIVERED";
-
- /*
- * Make sure that the following error codes are in sync with the ones
- * defined in dom/mobilemessage/interfaces/nsISmsRequestManager.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;
-
- 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/src/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/src/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/src/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 GeckoSmsManager() {
- SmsIOThread.getInstance().start();
- }
-
- public void start() {
- IntentFilter smsFilter = new IntentFilter();
- smsFilter.addAction(GeckoSmsManager.ACTION_SMS_RECEIVED);
- smsFilter.addAction(GeckoSmsManager.ACTION_SMS_SENT);
- smsFilter.addAction(GeckoSmsManager.ACTION_SMS_DELIVERED);
-
- GeckoApp.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]);
-
- GeckoAppShell.notifySmsReceived(msg.getDisplayOriginatingAddress(),
- msg.getDisplayMessageBody(),
- getGeckoMessageClass(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("GeckoSmsManager", "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("GeckoSmsManager", "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("GeckoSmsManager", "SMS part sending failed!");
- }
-
- if (envelope.arePartsRemaining(part)) {
- return;
- }
-
- if (envelope.isFailing(part)) {
- if (part == Envelope.SubParts.SENT_PART) {
- GeckoAppShell.notifySmsSendFailed(envelope.getError(),
- bundle.getInt("requestId"));
- Log.i("GeckoSmsManager", "SMS sending failed!");
- } else {
- GeckoAppShell.notifySmsDelivery(envelope.getMessageId(),
- kDeliveryStatusError,
- bundle.getString("number"),
- bundle.getString("message"),
- envelope.getMessageTimestamp());
- Log.i("GeckoSmsManager", "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);
-
- GeckoAppShell.notifySmsSent(id, number, message, timestamp,
- bundle.getInt("requestId"));
-
- envelope.setMessageId(id);
- envelope.setMessageTimestamp(timestamp);
-
- Log.i("GeckoSmsManager", "SMS sending was successfull!");
- } else {
- GeckoAppShell.notifySmsDelivery(envelope.getMessageId(),
- kDeliveryStatusSuccess,
- bundle.getString("number"),
- bundle.getString("message"),
- envelope.getMessageTimestamp());
- Log.i("GeckoSmsManager", "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(GeckoApp.mAppContext,
- PendingIntentUID.generate(), sentIntent,
- PendingIntent.FLAG_CANCEL_CURRENT);
-
- PendingIntent deliveredPendingIntent =
- PendingIntent.getBroadcast(GeckoApp.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(GeckoApp.mAppContext,
- PendingIntentUID.generate(), sentIntent,
- PendingIntent.FLAG_CANCEL_CURRENT)
- );
-
- deliveredPendingIntents.add(
- PendingIntent.getBroadcast(GeckoApp.mAppContext,
- PendingIntentUID.generate(), deliveredIntent,
- PendingIntent.FLAG_CANCEL_CURRENT)
- );
- }
-
- sm.sendMultipartTextMessage(aNumber, "", parts, sentPendingIntents,
- deliveredPendingIntents);
- }
- } catch (Exception e) {
- Log.e("GeckoSmsManager", "Failed to send an SMS: ", e);
-
- if (envelopeId != Postman.kUnknownEnvelopeId) {
- Postman.getInstance().destroyEnvelope(envelopeId);
- }
-
- GeckoAppShell.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 = GeckoApp.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("GeckoSmsManager", "The id we received is higher than the higher allowed value.");
- return -1;
- } catch (Exception e) {
- Log.e("GeckoSmsManager", "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 = GeckoApp.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 = getGeckoDeliveryStatus(cursor.getInt(cursor.getColumnIndex("status")));
- receiver = cursor.getString(cursor.getColumnIndex("address"));
- } else {
- throw new InvalidTypeException();
- }
-
- GeckoAppShell.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("GeckoSmsManager", "Message id " + mMessageId + " not found");
- GeckoAppShell.notifyGetSmsFailed(kNotFoundError, mRequestId);
- } catch (UnmatchingIdException e) {
- Log.e("GeckoSmsManager", "Requested message id (" + mMessageId +
- ") is different from the one we got.");
- GeckoAppShell.notifyGetSmsFailed(kUnknownError, mRequestId);
- } catch (TooManyResultsException e) {
- Log.e("GeckoSmsManager", "Get too many results for id " + mMessageId);
- GeckoAppShell.notifyGetSmsFailed(kUnknownError, mRequestId);
- } catch (InvalidTypeException e) {
- Log.i("GeckoSmsManager", "Message has an invalid type, we ignore it.");
- GeckoAppShell.notifyGetSmsFailed(kNotFoundError, mRequestId);
- } catch (Exception e) {
- Log.e("GeckoSmsManager", "Error while trying to get message: " + e);
- GeckoAppShell.notifyGetSmsFailed(kUnknownError, mRequestId);
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- }
- }
-
- if (!SmsIOThread.getInstance().execute(new GetMessageRunnable(aMessageId, aRequestId))) {
- Log.e("GeckoSmsManager", "Failed to add GetMessageRunnable to the SmsIOThread");
- GeckoAppShell.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 = GeckoApp.mAppContext.getContentResolver();
- Uri message = ContentUris.withAppendedId(kSmsContentUri, mMessageId);
-
- int count = cr.delete(message, null, null);
-
- if (count > 1) {
- throw new TooManyResultsException();
- }
-
- GeckoAppShell.notifySmsDeleted(count == 1, mRequestId);
- } catch (TooManyResultsException e) {
- Log.e("GeckoSmsManager", "Delete more than one message? " + e);
- GeckoAppShell.notifySmsDeleteFailed(kUnknownError, mRequestId);
- } catch (Exception e) {
- Log.e("GeckoSmsManager", "Error while trying to delete a message: " + e);
- GeckoAppShell.notifySmsDeleteFailed(kUnknownError, mRequestId);
- }
- }
- }
-
- if (!SmsIOThread.getInstance().execute(new DeleteMessageRunnable(aMessageId, aRequestId))) {
- Log.e("GeckoSmsManager", "Failed to add GetMessageRunnable to the SmsIOThread");
- GeckoAppShell.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 = GeckoApp.mAppContext.getContentResolver();
- cursor = cr.query(kSmsContentUri, kRequiredMessageRows, restrictionText, null,
- mReverse ? "date DESC" : "date ASC");
-
- if (cursor.getCount() == 0) {
- GeckoAppShell.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 = getGeckoDeliveryStatus(cursor.getInt(cursor.getColumnIndex("status")));
- receiver = cursor.getString(cursor.getColumnIndex("address"));
- } else {
- throw new UnexpectedDeliveryStateException();
- }
-
- int listId = MessagesListManager.getInstance().add(cursor);
- closeCursor = false;
- GeckoAppShell.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("GeckoSmsManager", "Unexcepted delivery state type: " + e);
- GeckoAppShell.notifyReadingMessageListFailed(kUnknownError, mRequestId);
- } catch (Exception e) {
- Log.e("GeckoSmsManager", "Error while trying to create a message list cursor: " + e);
- GeckoAppShell.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("GeckoSmsManager", "Failed to add CreateMessageListRunnable to the SmsIOThread");
- GeckoAppShell.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);
- GeckoAppShell.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 = getGeckoDeliveryStatus(cursor.getInt(cursor.getColumnIndex("status")));
- receiver = cursor.getString(cursor.getColumnIndex("address"));
- } else {
- throw new UnexpectedDeliveryStateException();
- }
-
- int listId = MessagesListManager.getInstance().add(cursor);
- GeckoAppShell.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("GeckoSmsManager", "Unexcepted delivery state type: " + e);
- GeckoAppShell.notifyReadingMessageListFailed(kUnknownError, mRequestId);
- } catch (Exception e) {
- Log.e("GeckoSmsManager", "Error while trying to get the next message of a list: " + e);
- GeckoAppShell.notifyReadingMessageListFailed(kUnknownError, mRequestId);
- }
- }
- }
-
- if (!SmsIOThread.getInstance().execute(new GetNextMessageInListRunnable(aListId, aRequestId))) {
- Log.e("GeckoSmsManager", "Failed to add GetNextMessageInListRunnable to the SmsIOThread");
- GeckoAppShell.notifyReadingMessageListFailed(kUnknownError, aRequestId);
- }
- }
-
- public void clearMessageList(int aListId) {
- MessagesListManager.getInstance().remove(aListId);
- }
-
- public void stop() {
- GeckoApp.mAppContext.unregisterReceiver(this);
- }
-
- public void shutdown() {
- SmsIOThread.getInstance().interrupt();
- MessagesListManager.getInstance().clear();
- }
-
- private int getGeckoDeliveryStatus(int aDeliveryStatus) {
- if (aDeliveryStatus == kInternalDeliveryStatusNone) {
- return kDeliveryStatusNotApplicable;
- }
- if (aDeliveryStatus >= kInternalDeliveryStatusFailed) {
- return kDeliveryStatusError;
- }
- if (aDeliveryStatus >= kInternalDeliveryStatusPending) {
- return kDeliveryStatusPending;
- }
- return kDeliveryStatusSuccess;
- }
-
- private int getGeckoMessageClass(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;
- }
-}
diff --git a/gfx/layers/ipc/GeckoContentController.h b/gfx/layers/ipc/GeckoContentController.h
deleted file mode 100644
index 7f59d47db..000000000
--- a/gfx/layers/ipc/GeckoContentController.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set sw=4 ts=8 et tw=80 : */
-/* 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/. */
-
-#ifndef mozilla_layers_GeckoContentController_h
-#define mozilla_layers_GeckoContentController_h
-
-#include "FrameMetrics.h"
-#include "nsISupportsImpl.h"
-
-class Task;
-
-namespace mozilla {
-namespace layers {
-
-class GeckoContentController {
-public:
- NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GeckoContentController)
-
- /**
- * Requests a paint of the given FrameMetrics |aFrameMetrics| from Gecko.
- * Implementations per-platform are responsible for actually handling this.
- */
- virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) = 0;
-
- /**
- * Requests handling of a double tap. |aPoint| is in CSS pixels, relative to
- * the current scroll offset. This should eventually round-trip back to
- * AsyncPanZoomController::ZoomToRect with the dimensions that we want to zoom
- * to.
- */
- virtual void HandleDoubleTap(const CSSIntPoint& aPoint) = 0;
-
- /**
- * Requests handling a single tap. |aPoint| is in CSS pixels, relative to the
- * current scroll offset. This should simulate and send to content a mouse
- * button down, then mouse button up at |aPoint|.
- */
- virtual void HandleSingleTap(const CSSIntPoint& aPoint) = 0;
-
- /**
- * Requests handling a long tap. |aPoint| is in CSS pixels, relative to the
- * current scroll offset.
- */
- virtual void HandleLongTap(const CSSIntPoint& aPoint) = 0;
-
- /**
- * Requests sending a mozbrowserasyncscroll domevent to embedder.
- * |aContentRect| is in CSS pixels, relative to the current cssPage.
- * |aScrollableSize| is the current content width/height in CSS pixels.
- */
- virtual void SendAsyncScrollDOMEvent(const CSSRect &aContentRect,
- const CSSSize &aScrollableSize) = 0;
-
- /**
- * Schedules a runnable to run on the controller/UI thread at some time
- * in the future.
- */
- virtual void PostDelayedTask(Task* aTask, int aDelayMs) = 0;
-
- GeckoContentController() {}
- virtual ~GeckoContentController() {}
-};
-
-}
-}
-
-#endif // mozilla_layers_GeckoContentController_h
diff --git a/ipc/glue/GeckoChildProcessHost.cpp b/ipc/glue/GeckoChildProcessHost.cpp
deleted file mode 100644
index b01062ffd..000000000
--- a/ipc/glue/GeckoChildProcessHost.cpp
+++ /dev/null
@@ -1,801 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- */
-/* 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/. */
-
-#include "GeckoChildProcessHost.h"
-
-#include "base/command_line.h"
-#include "base/path_service.h"
-#include "base/string_util.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/process_watcher.h"
-#ifdef MOZ_WIDGET_COCOA
-#include "chrome/common/mach_ipc_mac.h"
-#include "base/rand_util.h"
-#include "nsILocalFileMac.h"
-#endif
-
-#include "prprf.h"
-#include "prenv.h"
-
-#if defined(OS_LINUX)
-# define XP_LINUX 1
-#endif
-
-#include "nsDirectoryServiceDefs.h"
-#include "nsIFile.h"
-
-#include "mozilla/ipc/BrowserProcessSubThread.h"
-#include "mozilla/Omnijar.h"
-#include <sys/stat.h>
-
-#ifdef XP_WIN
-#include "nsIWinTaskbar.h"
-#define NS_TASKBAR_CONTRACTID "@mozilla.org/windows-taskbar;1"
-#endif
-
-using mozilla::MonitorAutoLock;
-using mozilla::ipc::GeckoChildProcessHost;
-
-#ifdef ANDROID
-// Like its predecessor in nsExceptionHandler.cpp, this is
-// the magic number of a file descriptor remapping we must
-// preserve for the child process.
-static const int kMagicAndroidSystemPropFd = 5;
-#endif
-
-static const bool kLowRightsSubprocesses =
- // We currently only attempt to drop privileges on gonk, because we
- // have no plugins or extensions to worry about breaking.
-#ifdef MOZ_WIDGET_GONK
- true
-#else
- false
-#endif
- ;
-
-static bool
-ShouldHaveDirectoryService()
-{
- return GeckoProcessType_Default == XRE_GetProcessType();
-}
-
-template<>
-struct RunnableMethodTraits<GeckoChildProcessHost>
-{
- static void RetainCallee(GeckoChildProcessHost* obj) { }
- static void ReleaseCallee(GeckoChildProcessHost* obj) { }
-};
-
-/*static*/
-base::ChildPrivileges
-GeckoChildProcessHost::DefaultChildPrivileges()
-{
- return (kLowRightsSubprocesses ?
- base::PRIVILEGES_UNPRIVILEGED : base::PRIVILEGES_INHERIT);
-}
-
-GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType,
- ChildPrivileges aPrivileges)
- : ChildProcessHost(RENDER_PROCESS), // FIXME/cjones: we should own this enum
- mProcessType(aProcessType),
- mPrivileges(aPrivileges),
- mMonitor("mozilla.ipc.GeckChildProcessHost.mMonitor"),
- mProcessState(CREATING_CHANNEL),
- mDelegate(nullptr),
- mChildProcessHandle(0)
-#if defined(MOZ_WIDGET_COCOA)
- , mChildTask(MACH_PORT_NULL)
-#endif
-{
- MOZ_COUNT_CTOR(GeckoChildProcessHost);
-
- MessageLoop* ioLoop = XRE_GetIOMessageLoop();
- ioLoop->PostTask(FROM_HERE,
- NewRunnableMethod(this,
- &GeckoChildProcessHost::InitializeChannel));
-}
-
-GeckoChildProcessHost::~GeckoChildProcessHost()
-
-{
- AssertIOThread();
-
- MOZ_COUNT_DTOR(GeckoChildProcessHost);
-
- if (mChildProcessHandle > 0)
- ProcessWatcher::EnsureProcessTerminated(mChildProcessHandle
-#if defined(NS_BUILD_REFCNT_LOGGING)
- , false // don't "force"
-#endif
- );
-
-#if defined(MOZ_WIDGET_COCOA)
- if (mChildTask != MACH_PORT_NULL)
- mach_port_deallocate(mach_task_self(), mChildTask);
-#endif
-}
-
-void GetPathToBinary(FilePath& exePath)
-{
- if (ShouldHaveDirectoryService()) {
- nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
- NS_ASSERTION(directoryService, "Expected XPCOM to be available");
- if (directoryService) {
- nsCOMPtr<nsIFile> greDir;
- nsresult rv = directoryService->Get(NS_GRE_DIR, NS_GET_IID(nsIFile), getter_AddRefs(greDir));
- if (NS_SUCCEEDED(rv)) {
-#ifdef OS_WIN
- nsString path;
- greDir->GetPath(path);
-#else
- nsCString path;
- greDir->GetNativePath(path);
-#endif
- exePath = FilePath(path.get());
-#ifdef MOZ_WIDGET_COCOA
- // We need to use an App Bundle on OS X so that we can hide
- // the dock icon. See Bug 557225.
- exePath = exePath.AppendASCII(MOZ_CHILD_PROCESS_BUNDLE);
-#endif
- }
- }
- }
-
- if (exePath.empty()) {
-#ifdef OS_WIN
- exePath = FilePath::FromWStringHack(CommandLine::ForCurrentProcess()->program());
-#else
- exePath = FilePath(CommandLine::ForCurrentProcess()->argv()[0]);
-#endif
- exePath = exePath.DirName();
- }
-
- exePath = exePath.AppendASCII(MOZ_CHILD_PROCESS_NAME);
-}
-
-#ifdef MOZ_WIDGET_COCOA
-class AutoCFTypeObject {
-public:
- AutoCFTypeObject(CFTypeRef object)
- {
- mObject = object;
- }
- ~AutoCFTypeObject()
- {
- ::CFRelease(mObject);
- }
-private:
- CFTypeRef mObject;
-};
-#endif
-
-nsresult GeckoChildProcessHost::GetArchitecturesForBinary(const char *path, uint32_t *result)
-{
- *result = 0;
-
-#ifdef MOZ_WIDGET_COCOA
- CFURLRef url = ::CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
- (const UInt8*)path,
- strlen(path),
- false);
- if (!url) {
- return NS_ERROR_FAILURE;
- }
- AutoCFTypeObject autoPluginContainerURL(url);
-
- CFArrayRef pluginContainerArchs = ::CFBundleCopyExecutableArchitecturesForURL(url);
- if (!pluginContainerArchs) {
- return NS_ERROR_FAILURE;
- }
- AutoCFTypeObject autoPluginContainerArchs(pluginContainerArchs);
-
- CFIndex pluginArchCount = ::CFArrayGetCount(pluginContainerArchs);
- for (CFIndex i = 0; i < pluginArchCount; i++) {
- CFNumberRef currentArch = static_cast<CFNumberRef>(::CFArrayGetValueAtIndex(pluginContainerArchs, i));
- int currentArchInt = 0;
- if (!::CFNumberGetValue(currentArch, kCFNumberIntType, &currentArchInt)) {
- continue;
- }
- switch (currentArchInt) {
- case kCFBundleExecutableArchitectureI386:
- *result |= base::PROCESS_ARCH_I386;
- break;
- case kCFBundleExecutableArchitectureX86_64:
- *result |= base::PROCESS_ARCH_X86_64;
- break;
- case kCFBundleExecutableArchitecturePPC:
- *result |= base::PROCESS_ARCH_PPC;
- break;
- default:
- break;
- }
- }
-
- return (*result ? NS_OK : NS_ERROR_FAILURE);
-#else
- return NS_ERROR_NOT_IMPLEMENTED;
-#endif
-}
-
-uint32_t GeckoChildProcessHost::GetSupportedArchitecturesForProcessType(GeckoProcessType type)
-{
-#ifdef MOZ_WIDGET_COCOA
- if (type == GeckoProcessType_Plugin) {
- // Cache this, it shouldn't ever change.
- static uint32_t pluginContainerArchs = 0;
- if (pluginContainerArchs == 0) {
- FilePath exePath;
- GetPathToBinary(exePath);
- nsresult rv = GetArchitecturesForBinary(exePath.value().c_str(), &pluginContainerArchs);
- NS_ASSERTION(NS_SUCCEEDED(rv) && pluginContainerArchs != 0, "Getting architecture of plugin container failed!");
- if (NS_FAILED(rv) || pluginContainerArchs == 0) {
- pluginContainerArchs = base::GetCurrentProcessArchitecture();
- }
- }
- return pluginContainerArchs;
- }
-#endif
-
- return base::GetCurrentProcessArchitecture();
-}
-
-void
-GeckoChildProcessHost::PrepareLaunch()
-{
-#ifdef XP_WIN
- InitWindowsGroupID();
-#endif
-}
-
-#ifdef XP_WIN
-void GeckoChildProcessHost::InitWindowsGroupID()
-{
- // On Win7+, pass the application user model to the child, so it can
- // register with it. This insures windows created by the container
- // properly group with the parent app on the Win7 taskbar.
- nsCOMPtr<nsIWinTaskbar> taskbarInfo =
- do_GetService(NS_TASKBAR_CONTRACTID);
- if (taskbarInfo) {
- bool isSupported = false;
- taskbarInfo->GetAvailable(&isSupported);
- nsAutoString appId;
- if (isSupported && NS_SUCCEEDED(taskbarInfo->GetDefaultGroupId(appId))) {
- mGroupId.Append(appId);
- } else {
- mGroupId.AssignLiteral("-");
- }
- }
-}
-#endif
-
-bool
-GeckoChildProcessHost::SyncLaunch(std::vector<std::string> aExtraOpts, int aTimeoutMs, base::ProcessArchitecture arch)
-{
- PrepareLaunch();
-
- PRIntervalTime timeoutTicks = (aTimeoutMs > 0) ?
- PR_MillisecondsToInterval(aTimeoutMs) : PR_INTERVAL_NO_TIMEOUT;
- MessageLoop* ioLoop = XRE_GetIOMessageLoop();
- NS_ASSERTION(MessageLoop::current() != ioLoop, "sync launch from the IO thread NYI");
-
- ioLoop->PostTask(FROM_HERE,
- NewRunnableMethod(this,
- &GeckoChildProcessHost::PerformAsyncLaunch,
- aExtraOpts, arch));
- // NB: this uses a different mechanism than the chromium parent
- // class.
- MonitorAutoLock lock(mMonitor);
- PRIntervalTime waitStart = PR_IntervalNow();
- PRIntervalTime current;
-
- // We'll receive several notifications, we need to exit when we
- // have either successfully launched or have timed out.
- while (mProcessState < PROCESS_CONNECTED) {
- lock.Wait(timeoutTicks);
-
- if (timeoutTicks != PR_INTERVAL_NO_TIMEOUT) {
- current = PR_IntervalNow();
- PRIntervalTime elapsed = current - waitStart;
- if (elapsed > timeoutTicks) {
- break;
- }
- timeoutTicks = timeoutTicks - elapsed;
- waitStart = current;
- }
- }
-
- return mProcessState == PROCESS_CONNECTED;
-}
-
-bool
-GeckoChildProcessHost::AsyncLaunch(std::vector<std::string> aExtraOpts)
-{
- PrepareLaunch();
-
- MessageLoop* ioLoop = XRE_GetIOMessageLoop();
- ioLoop->PostTask(FROM_HERE,
- NewRunnableMethod(this,
- &GeckoChildProcessHost::PerformAsyncLaunch,
- aExtraOpts, base::GetCurrentProcessArchitecture()));
-
- // This may look like the sync launch wait, but we only delay as
- // long as it takes to create the channel.
- MonitorAutoLock lock(mMonitor);
- while (mProcessState < CHANNEL_INITIALIZED) {
- lock.Wait();
- }
-
- return true;
-}
-
-bool
-GeckoChildProcessHost::LaunchAndWaitForProcessHandle(StringVector aExtraOpts)
-{
- PrepareLaunch();
-
- MessageLoop* ioLoop = XRE_GetIOMessageLoop();
- ioLoop->PostTask(FROM_HERE,
- NewRunnableMethod(this,
- &GeckoChildProcessHost::PerformAsyncLaunch,
- aExtraOpts, base::GetCurrentProcessArchitecture()));
-
- MonitorAutoLock lock(mMonitor);
- while (mProcessState < PROCESS_CREATED) {
- lock.Wait();
- }
- MOZ_ASSERT(mProcessState == PROCESS_ERROR || mChildProcessHandle);
-
- return mProcessState < PROCESS_ERROR;
-}
-
-void
-GeckoChildProcessHost::InitializeChannel()
-{
- CreateChannel();
-
- MonitorAutoLock lock(mMonitor);
- mProcessState = CHANNEL_INITIALIZED;
- lock.Notify();
-}
-
-void
-GeckoChildProcessHost::Join()
-{
- AssertIOThread();
-
- if (!mChildProcessHandle) {
- return;
- }
-
- // If this fails, there's nothing we can do.
- base::KillProcess(mChildProcessHandle, 0, /*wait*/true);
- mChildProcessHandle = 0;
-}
-
-int32_t GeckoChildProcessHost::mChildCounter = 0;
-
-//
-// Wrapper function for handling GECKO_SEPARATE_NSPR_LOGS
-//
-bool
-GeckoChildProcessHost::PerformAsyncLaunch(std::vector<std::string> aExtraOpts, base::ProcessArchitecture arch)
-{
- // If separate NSPR log files are not requested, we're done.
- const char* origLogName = PR_GetEnv("NSPR_LOG_FILE");
- const char* separateLogs = PR_GetEnv("GECKO_SEPARATE_NSPR_LOGS");
- if (!origLogName || !separateLogs || !*separateLogs ||
- *separateLogs == '0' || *separateLogs == 'N' || *separateLogs == 'n') {
- return PerformAsyncLaunchInternal(aExtraOpts, arch);
- }
-
- // We currently have no portable way to launch child with environment
- // different than parent. So temporarily change NSPR_LOG_FILE so child
- // inherits value we want it to have. (NSPR only looks at NSPR_LOG_FILE at
- // startup, so it's 'safe' to play with the parent's environment this way.)
- nsAutoCString setChildLogName("NSPR_LOG_FILE=");
- setChildLogName.Append(origLogName);
-
- // remember original value so we can restore it.
- // - buffer needs to be permanently allocated for PR_SetEnv()
- // - Note: this code is not called re-entrantly, nor are restoreOrigLogName
- // or mChildCounter touched by any other thread, so this is safe.
- static char* restoreOrigLogName = 0;
- if (!restoreOrigLogName)
- restoreOrigLogName = strdup(setChildLogName.get());
-
- // Append child-specific postfix to name
- setChildLogName.AppendLiteral(".child-");
- setChildLogName.AppendInt(++mChildCounter);
-
- // Passing temporary to PR_SetEnv is ok here because env gets copied
- // by exec, etc., to permanent storage in child when process launched.
- PR_SetEnv(setChildLogName.get());
- bool retval = PerformAsyncLaunchInternal(aExtraOpts, arch);
-
- // Revert to original value
- PR_SetEnv(restoreOrigLogName);
-
- return retval;
-}
-
-void
-#if defined(XP_WIN)
-AddAppDirToCommandLine(CommandLine& aCmdLine)
-#else
-AddAppDirToCommandLine(std::vector<std::string>& aCmdLine)
-#endif
-{
- // Content processes need access to application resources, so pass
- // the full application directory path to the child process.
- if (ShouldHaveDirectoryService()) {
- nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
- NS_ASSERTION(directoryService, "Expected XPCOM to be available");
- if (directoryService) {
- nsCOMPtr<nsIFile> appDir;
- // NS_XPCOM_CURRENT_PROCESS_DIR really means the app dir, not the
- // current process dir.
- nsresult rv = directoryService->Get(NS_XPCOM_CURRENT_PROCESS_DIR,
- NS_GET_IID(nsIFile),
- getter_AddRefs(appDir));
- if (NS_SUCCEEDED(rv)) {
- nsAutoCString path;
- appDir->GetNativePath(path);
-#if defined(XP_WIN)
- aCmdLine.AppendLooseValue(UTF8ToWide("-appdir"));
- aCmdLine.AppendLooseValue(UTF8ToWide(path.get()));
-#else
- aCmdLine.push_back("-appdir");
- aCmdLine.push_back(path.get());
-#endif
- }
- }
- }
-}
-
-bool
-GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector<std::string>& aExtraOpts, base::ProcessArchitecture arch)
-{
- // We rely on the fact that InitializeChannel() has already been processed
- // on the IO thread before this point is reached.
- if (!GetChannel()) {
- return false;
- }
-
- base::ProcessHandle process;
-
- // send the child the PID so that it can open a ProcessHandle back to us.
- // probably don't want to do this in the long run
- char pidstring[32];
- PR_snprintf(pidstring, sizeof(pidstring) - 1,
- "%ld", base::Process::Current().pid());
-
- const char* const childProcessType =
- XRE_ChildProcessTypeToString(mProcessType);
-
-//--------------------------------------------------
-#if defined(OS_POSIX)
- // For POSIX, we have to be extremely anal about *not* using
- // std::wstring in code compiled with Mozilla's -fshort-wchar
- // configuration, because chromium is compiled with -fno-short-wchar
- // and passing wstrings from one config to the other is unsafe. So
- // we split the logic here.
-
-#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_BSD)
- base::environment_map newEnvVars;
- ChildPrivileges privs = mPrivileges;
- if (privs == base::PRIVILEGES_DEFAULT) {
- privs = DefaultChildPrivileges();
- }
- // XPCOM may not be initialized in some subprocesses. We don't want
- // to initialize XPCOM just for the directory service, especially
- // since LD_LIBRARY_PATH is already set correctly in subprocesses
- // (meaning that we don't need to set that up in the environment).
- if (ShouldHaveDirectoryService()) {
- nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
- NS_ASSERTION(directoryService, "Expected XPCOM to be available");
- if (directoryService) {
- nsCOMPtr<nsIFile> greDir;
- nsresult rv = directoryService->Get(NS_GRE_DIR, NS_GET_IID(nsIFile), getter_AddRefs(greDir));
- if (NS_SUCCEEDED(rv)) {
- nsCString path;
- greDir->GetNativePath(path);
-# if defined(OS_LINUX) || defined(OS_BSD)
-# if defined(MOZ_WIDGET_ANDROID)
- path += "/lib";
-# endif // MOZ_WIDGET_ANDROID
- const char *ld_library_path = PR_GetEnv("LD_LIBRARY_PATH");
- nsCString new_ld_lib_path;
- if (ld_library_path && *ld_library_path) {
- new_ld_lib_path.Assign(path.get());
- new_ld_lib_path.AppendLiteral(":");
- new_ld_lib_path.Append(ld_library_path);
- newEnvVars["LD_LIBRARY_PATH"] = new_ld_lib_path.get();
- } else {
- newEnvVars["LD_LIBRARY_PATH"] = path.get();
- }
-# elif OS_MACOSX
- newEnvVars["DYLD_LIBRARY_PATH"] = path.get();
- // XXX DYLD_INSERT_LIBRARIES should only be set when launching a plugin
- // process, and has no effect on other subprocesses (the hooks in
- // libplugin_child_interpose.dylib become noops). But currently it
- // gets set when launching any kind of subprocess.
- //
- // Trigger "dyld interposing" for the dylib that contains
- // plugin_child_interpose.mm. This allows us to hook OS calls in the
- // plugin process (ones that don't work correctly in a background
- // process). Don't break any other "dyld interposing" that has already
- // been set up by whatever may have launched the browser.
- const char* prevInterpose = PR_GetEnv("DYLD_INSERT_LIBRARIES");
- nsCString interpose;
- if (prevInterpose) {
- interpose.Assign(prevInterpose);
- interpose.AppendLiteral(":");
- }
- interpose.Append(path.get());
- interpose.AppendLiteral("/libplugin_child_interpose.dylib");
- newEnvVars["DYLD_INSERT_LIBRARIES"] = interpose.get();
-# endif // OS_LINUX
- }
- }
- }
-#endif // OS_LINUX || OS_MACOSX
-
- FilePath exePath;
- GetPathToBinary(exePath);
-
-#ifdef MOZ_WIDGET_ANDROID
- // The java wrapper unpacks this for us but can't make it executable
- chmod(exePath.value().c_str(), 0700);
-#endif // MOZ_WIDGET_ANDROID
-
-#ifdef ANDROID
- // Remap the Android property workspace to a well-known int,
- // and update the environment to reflect the new value for the
- // child process.
- const char *apws = getenv("ANDROID_PROPERTY_WORKSPACE");
- if (apws) {
- int fd = atoi(apws);
- mFileMap.push_back(std::pair<int, int>(fd, kMagicAndroidSystemPropFd));
-
- char buf[32];
- char *szptr = strchr(apws, ',');
-
- snprintf(buf, sizeof(buf), "%d%s", kMagicAndroidSystemPropFd, szptr);
- newEnvVars["ANDROID_PROPERTY_WORKSPACE"] = buf;
- }
-#endif // ANDROID
-
-#ifdef MOZ_WIDGET_GONK
- if (const char *ldPreloadPath = getenv("LD_PRELOAD")) {
- newEnvVars["LD_PRELOAD"] = ldPreloadPath;
- }
-#endif // MOZ_WIDGET_GONK
-
- // remap the IPC socket fd to a well-known int, as the OS does for
- // STDOUT_FILENO, for example
- int srcChannelFd, dstChannelFd;
- channel().GetClientFileDescriptorMapping(&srcChannelFd, &dstChannelFd);
- mFileMap.push_back(std::pair<int,int>(srcChannelFd, dstChannelFd));
-
- // no need for kProcessChannelID, the child process inherits the
- // other end of the socketpair() from us
-
- std::vector<std::string> childArgv;
-
- childArgv.push_back(exePath.value());
-
- childArgv.insert(childArgv.end(), aExtraOpts.begin(), aExtraOpts.end());
-
- if (Omnijar::IsInitialized()) {
- // Make sure that child processes can find the omnijar
- // See XRE_InitCommandLine in nsAppRunner.cpp
- nsAutoCString path;
- nsCOMPtr<nsIFile> file = Omnijar::GetPath(Omnijar::GRE);
- if (file && NS_SUCCEEDED(file->GetNativePath(path))) {
- childArgv.push_back("-greomni");
- childArgv.push_back(path.get());
- }
- file = Omnijar::GetPath(Omnijar::APP);
- if (file && NS_SUCCEEDED(file->GetNativePath(path))) {
- childArgv.push_back("-appomni");
- childArgv.push_back(path.get());
- }
- }
-
- // Add the application directory path (-appdir path)
- AddAppDirToCommandLine(childArgv);
-
- childArgv.push_back(pidstring);
-
-#ifdef MOZ_WIDGET_COCOA
- // Add a mach port to the command line so the child can communicate its
- // 'task_t' back to the parent.
- //
- // Put a random number into the channel name, so that a compromised renderer
- // can't pretend being the child that's forked off.
- std::string mach_connection_name = StringPrintf("org.mozilla.machname.%d",
- base::RandInt(0, std::numeric_limits<int>::max()));
- childArgv.push_back(mach_connection_name.c_str());
-#endif
-
- childArgv.push_back(childProcessType);
-
- base::LaunchApp(childArgv, mFileMap,
-#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_BSD)
- newEnvVars, privs,
-#endif
- false, &process, arch);
-
-#ifdef MOZ_WIDGET_COCOA
- // Wait for the child process to send us its 'task_t' data.
- const int kTimeoutMs = 10000;
-
- MachReceiveMessage child_message;
- ReceivePort parent_recv_port(mach_connection_name.c_str());
- kern_return_t err = parent_recv_port.WaitForMessage(&child_message, kTimeoutMs);
- if (err != KERN_SUCCESS) {
- std::string errString = StringPrintf("0x%x %s", err, mach_error_string(err));
- LOG(ERROR) << "parent WaitForMessage() failed: " << errString;
- return false;
- }
-
- task_t child_task = child_message.GetTranslatedPort(0);
- if (child_task == MACH_PORT_NULL) {
- LOG(ERROR) << "parent GetTranslatedPort(0) failed.";
- return false;
- }
-
- if (child_message.GetTranslatedPort(1) == MACH_PORT_NULL) {
- LOG(ERROR) << "parent GetTranslatedPort(1) failed.";
- return false;
- }
- MachPortSender parent_sender(child_message.GetTranslatedPort(1));
-
- MachSendMessage parent_message(/* id= */0);
- if (!parent_message.AddDescriptor(bootstrap_port)) {
- LOG(ERROR) << "parent AddDescriptor(" << bootstrap_port << ") failed.";
- return false;
- }
-
- err = parent_sender.SendMessage(parent_message, kTimeoutMs);
- if (err != KERN_SUCCESS) {
- std::string errString = StringPrintf("0x%x %s", err, mach_error_string(err));
- LOG(ERROR) << "parent SendMessage() failed: " << errString;
- return false;
- }
-#endif
-
-//--------------------------------------------------
-#elif defined(OS_WIN)
-
- FilePath exePath;
- GetPathToBinary(exePath);
-
- CommandLine cmdLine(exePath.ToWStringHack());
- cmdLine.AppendSwitchWithValue(switches::kProcessChannelID, channel_id());
-
- for (std::vector<std::string>::iterator it = aExtraOpts.begin();
- it != aExtraOpts.end();
- ++it) {
- cmdLine.AppendLooseValue(UTF8ToWide(*it));
- }
-
- if (Omnijar::IsInitialized()) {
- // Make sure the child process can find the omnijar
- // See XRE_InitCommandLine in nsAppRunner.cpp
- nsAutoString path;
- nsCOMPtr<nsIFile> file = Omnijar::GetPath(Omnijar::GRE);
- if (file && NS_SUCCEEDED(file->GetPath(path))) {
- cmdLine.AppendLooseValue(UTF8ToWide("-greomni"));
- cmdLine.AppendLooseValue(path.get());
- }
- file = Omnijar::GetPath(Omnijar::APP);
- if (file && NS_SUCCEEDED(file->GetPath(path))) {
- cmdLine.AppendLooseValue(UTF8ToWide("-appomni"));
- cmdLine.AppendLooseValue(path.get());
- }
- }
-
- // Add the application directory path (-appdir path)
- AddAppDirToCommandLine(cmdLine);
-
- // XXX Command line params past this point are expected to be at
- // the end of the command line string, and in a specific order.
- // See XRE_InitChildProcess in nsEmbedFunction.
-
- // Win app model id
- cmdLine.AppendLooseValue(std::wstring(mGroupId.get()));
-
- // Process id
- cmdLine.AppendLooseValue(UTF8ToWide(pidstring));
-
- // Process type
- cmdLine.AppendLooseValue(UTF8ToWide(childProcessType));
-
- base::LaunchApp(cmdLine, false, false, &process);
-
-#else
-# error Sorry
-#endif
-
- if (!process) {
- MonitorAutoLock lock(mMonitor);
- mProcessState = PROCESS_ERROR;
- lock.Notify();
- return false;
- }
- // NB: on OS X, we block much longer than we need to in order to
- // reach this call, waiting for the child process's task_t. The
- // best way to fix that is to refactor this file, hard.
- SetHandle(process);
-#if defined(MOZ_WIDGET_COCOA)
- mChildTask = child_task;
-#endif
-
- OpenPrivilegedHandle(base::GetProcId(process));
- {
- MonitorAutoLock lock(mMonitor);
- mProcessState = PROCESS_CREATED;
- lock.Notify();
- }
-
- return true;
-}
-
-void
-GeckoChildProcessHost::OpenPrivilegedHandle(base::ProcessId aPid)
-{
- if (mChildProcessHandle) {
- MOZ_ASSERT(aPid == base::GetProcId(mChildProcessHandle));
- return;
- }
- if (!base::OpenPrivilegedProcessHandle(aPid, &mChildProcessHandle)) {
- NS_RUNTIMEABORT("can't open handle to child process");
- }
-}
-
-void
-GeckoChildProcessHost::OnChannelConnected(int32_t peer_pid)
-{
- OpenPrivilegedHandle(peer_pid);
- {
- MonitorAutoLock lock(mMonitor);
- mProcessState = PROCESS_CONNECTED;
- lock.Notify();
- }
-}
-
-void
-GeckoChildProcessHost::OnMessageReceived(const IPC::Message& aMsg)
-{
- // We never process messages ourself, just save them up for the next
- // listener.
- mQueue.push(aMsg);
-}
-
-void
-GeckoChildProcessHost::OnChannelError()
-{
- // FIXME/bug 773925: save up this error for the next listener.
-}
-
-void
-GeckoChildProcessHost::GetQueuedMessages(std::queue<IPC::Message>& queue)
-{
- // If this is called off the IO thread, bad things will happen.
- DCHECK(MessageLoopForIO::current());
- swap(queue, mQueue);
- // We expect the next listener to take over processing of our queue.
-}
-
-void
-GeckoChildProcessHost::OnWaitableEventSignaled(base::WaitableEvent *event)
-{
- if (mDelegate) {
- mDelegate->OnWaitableEventSignaled(event);
- }
- ChildProcessHost::OnWaitableEventSignaled(event);
-}
diff --git a/ipc/glue/GeckoChildProcessHost.h b/ipc/glue/GeckoChildProcessHost.h
deleted file mode 100644
index 46c70307a..000000000
--- a/ipc/glue/GeckoChildProcessHost.h
+++ /dev/null
@@ -1,171 +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/. */
-
-#ifndef __IPC_GLUE_GECKOCHILDPROCESSHOST_H__
-#define __IPC_GLUE_GECKOCHILDPROCESSHOST_H__
-
-#include "base/file_path.h"
-#include "base/process_util.h"
-#include "base/scoped_ptr.h"
-#include "base/waitable_event.h"
-#include "chrome/common/child_process_host.h"
-
-#include "mozilla/Monitor.h"
-
-#include "nsXULAppAPI.h" // for GeckoProcessType
-#include "nsString.h"
-
-namespace mozilla {
-namespace ipc {
-
-class GeckoChildProcessHost : public ChildProcessHost
-{
-protected:
- typedef mozilla::Monitor Monitor;
- typedef std::vector<std::string> StringVector;
-
-public:
- typedef base::ChildPrivileges ChildPrivileges;
- typedef base::ProcessHandle ProcessHandle;
-
- static ChildPrivileges DefaultChildPrivileges();
-
- GeckoChildProcessHost(GeckoProcessType aProcessType,
- ChildPrivileges aPrivileges=base::PRIVILEGES_DEFAULT);
-
- ~GeckoChildProcessHost();
-
- static nsresult GetArchitecturesForBinary(const char *path, uint32_t *result);
-
- static uint32_t GetSupportedArchitecturesForProcessType(GeckoProcessType type);
-
- // Block until the IPC channel for our subprocess is initialized,
- // but no longer. The child process may or may not have been
- // created when this method returns.
- bool AsyncLaunch(StringVector aExtraOpts=StringVector());
-
- // Block until the IPC channel for our subprocess is initialized and
- // the OS process is created. The subprocess may or may not have
- // connected back to us when this method returns.
- //
- // NB: on POSIX, this method is relatively cheap, and doesn't
- // require disk IO. On win32 however, it requires at least the
- // analogue of stat(). This difference induces a semantic
- // difference in this method: on POSIX, when we return, we know the
- // subprocess has been created, but we don't know whether its
- // executable image can be loaded. On win32, we do know that when
- // we return. But we don't know if dynamic linking succeeded on
- // either platform.
- bool LaunchAndWaitForProcessHandle(StringVector aExtraOpts=StringVector());
-
- // Block until the child process has been created and it connects to
- // the IPC channel, meaning it's fully initialized. (Or until an
- // error occurs.)
- bool SyncLaunch(StringVector aExtraOpts=StringVector(),
- int32_t timeoutMs=0,
- base::ProcessArchitecture arch=base::GetCurrentProcessArchitecture());
-
- bool PerformAsyncLaunch(StringVector aExtraOpts=StringVector(),
- base::ProcessArchitecture arch=base::GetCurrentProcessArchitecture());
-
- virtual void OnChannelConnected(int32_t peer_pid);
- virtual void OnMessageReceived(const IPC::Message& aMsg);
- virtual void OnChannelError();
- virtual void GetQueuedMessages(std::queue<IPC::Message>& queue);
-
- void InitializeChannel();
-
- virtual bool CanShutdown() { return true; }
-
- virtual void OnWaitableEventSignaled(base::WaitableEvent *event);
-
- IPC::Channel* GetChannel() {
- return channelp();
- }
-
- base::WaitableEvent* GetShutDownEvent() {
- return GetProcessEvent();
- }
-
- ProcessHandle GetChildProcessHandle() {
- return mChildProcessHandle;
- }
-
-#ifdef XP_MACOSX
- task_t GetChildTask() {
- return mChildTask;
- }
-#endif
-
- /**
- * Must run on the IO thread. Cause the OS process to exit and
- * ensure its OS resources are cleaned up.
- */
- void Join();
-
-protected:
- GeckoProcessType mProcessType;
- ChildPrivileges mPrivileges;
- Monitor mMonitor;
- FilePath mProcessPath;
- // This value must be accessed while holding mMonitor.
- enum {
- // This object has been constructed, but the OS process has not
- // yet.
- CREATING_CHANNEL = 0,
- // The IPC channel for our subprocess has been created, but the OS
- // process has still not been created.
- CHANNEL_INITIALIZED,
- // The OS process has been created, but it hasn't yet connected to
- // our IPC channel.
- PROCESS_CREATED,
- // The process is launched and connected to our IPC channel. All
- // is well.
- PROCESS_CONNECTED,
- PROCESS_ERROR
- } mProcessState;
-
- static int32_t mChildCounter;
-
- void PrepareLaunch();
-
-#ifdef XP_WIN
- void InitWindowsGroupID();
- nsString mGroupId;
-#endif
-
-#if defined(OS_POSIX)
- base::file_handle_mapping_vector mFileMap;
-#endif
-
- base::WaitableEventWatcher::Delegate* mDelegate;
-
- ProcessHandle mChildProcessHandle;
-#if defined(OS_MACOSX)
- task_t mChildTask;
-#endif
-
-private:
- DISALLOW_EVIL_CONSTRUCTORS(GeckoChildProcessHost);
-
- // Does the actual work for AsyncLaunch, on the IO thread.
- bool PerformAsyncLaunchInternal(std::vector<std::string>& aExtraOpts,
- base::ProcessArchitecture arch);
-
- void OpenPrivilegedHandle(base::ProcessId aPid);
-
- // In between launching the subprocess and handing off its IPC
- // channel, there's a small window of time in which *we* might still
- // be the channel listener, and receive messages. That's bad
- // because we have no idea what to do with those messages. So queue
- // them here until we hand off the eventual listener.
- //
- // FIXME/cjones: this strongly indicates bad design. Shame on us.
- std::queue<IPC::Message> mQueue;
-};
-
-} /* namespace ipc */
-} /* namespace mozilla */
-
-#endif /* __IPC_GLUE_GECKOCHILDPROCESSHOST_H__ */
diff --git a/mobile/android/base/GeckoAccessibility.java b/mobile/android/base/GeckoAccessibility.java
deleted file mode 100644
index 5f133fcda..000000000
--- a/mobile/android/base/GeckoAccessibility.java
+++ /dev/null
@@ -1,379 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; 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.gecko;
-
-import org.mozilla.gecko.gfx.LayerView;
-import org.mozilla.gecko.util.ThreadUtils;
-import org.mozilla.gecko.util.UiAsyncTask;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import android.app.ActivityManager;
-import android.app.ActivityManager.RunningServiceInfo;
-import android.content.Context;
-import android.graphics.Rect;
-import android.os.Build;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.View;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.accessibility.AccessibilityNodeProvider;
-
-import com.googlecode.eyesfree.braille.selfbraille.SelfBrailleClient;
-import com.googlecode.eyesfree.braille.selfbraille.WriteData;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-
-public class GeckoAccessibility {
- private static final String LOGTAG = "GeckoAccessibility";
- private static final int VIRTUAL_CURSOR_PREVIOUS = 1;
- private static final int VIRTUAL_CURSOR_POSITION = 2;
- private static final int VIRTUAL_CURSOR_NEXT = 3;
-
- private static boolean sEnabled = false;
- // Used to store the JSON message and populate the event later in the code path.
- private static JSONObject sEventMessage = null;
- private static AccessibilityNodeInfo sVirtualCursorNode = null;
-
- private static SelfBrailleClient sSelfBrailleClient = null;
-
- private static final HashSet<String> sServiceWhitelist =
- new HashSet<String>(Arrays.asList(new String[] {
- "com.google.android.marvin.talkback.TalkBackService", // Google Talkback screen reader
- "com.mot.readout.ScreenReader", // Motorola screen reader
- "info.spielproject.spiel.SpielService", // Spiel screen reader
- "es.codefactory.android.app.ma.MAAccessibilityService" // Codefactory Mobile Accessibility screen reader
- }));
-
- public static void updateAccessibilitySettings (final GeckoApp app) {
- new UiAsyncTask<Void, Void, Void>(ThreadUtils.getBackgroundHandler()) {
- @Override
- public Void doInBackground(Void... args) {
- JSONObject ret = new JSONObject();
- sEnabled = false;
- AccessibilityManager accessibilityManager =
- (AccessibilityManager) app.getSystemService(Context.ACCESSIBILITY_SERVICE);
- if (accessibilityManager.isEnabled()) {
- ActivityManager activityManager =
- (ActivityManager) app.getSystemService(Context.ACTIVITY_SERVICE);
- List<RunningServiceInfo> runningServices = activityManager.getRunningServices(Integer.MAX_VALUE);
-
- for (RunningServiceInfo runningServiceInfo : runningServices) {
- sEnabled = sServiceWhitelist.contains(runningServiceInfo.service.getClassName());
- if (sEnabled)
- break;
- }
- if (sEnabled && sSelfBrailleClient == null &&
- Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
- sSelfBrailleClient = new SelfBrailleClient(GeckoAppShell.getContext(), false);
- }
- }
-
- try {
- ret.put("enabled", sEnabled);
- } catch (Exception ex) {
- Log.e(LOGTAG, "Error building JSON arguments for Accessibility:Settings:", ex);
- }
-
- GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Accessibility:Settings",
- ret.toString()));
- return null;
- }
-
- @Override
- public void onPostExecute(Void args) {
- // Disable the dynamic toolbar when enabling accessibility.
- // These features tend not to interact well.
- app.setAccessibilityEnabled(sEnabled);
- }
- }.execute();
- }
-
- private static void populateEventFromJSON (AccessibilityEvent event, JSONObject message) {
- final JSONArray textArray = message.optJSONArray("text");
- if (textArray != null) {
- for (int i = 0; i < textArray.length(); i++)
- event.getText().add(textArray.optString(i));
- }
-
- event.setContentDescription(message.optString("description"));
- event.setEnabled(message.optBoolean("enabled", true));
- event.setChecked(message.optBoolean("checked"));
- event.setPassword(message.optBoolean("password"));
- event.setAddedCount(message.optInt("addedCount", -1));
- event.setRemovedCount(message.optInt("removedCount", -1));
- event.setFromIndex(message.optInt("fromIndex", -1));
- event.setItemCount(message.optInt("itemCount", -1));
- event.setCurrentItemIndex(message.optInt("currentItemIndex", -1));
- event.setBeforeText(message.optString("beforeText"));
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
- event.setToIndex(message.optInt("toIndex", -1));
- event.setScrollable(message.optBoolean("scrollable"));
- event.setScrollX(message.optInt("scrollX", -1));
- event.setScrollY(message.optInt("scrollY", -1));
- }
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
- event.setMaxScrollX(message.optInt("maxScrollX", -1));
- event.setMaxScrollY(message.optInt("maxScrollY", -1));
- }
- }
-
- private static void sendDirectAccessibilityEvent(int eventType, JSONObject message) {
- final AccessibilityEvent accEvent = AccessibilityEvent.obtain(eventType);
- accEvent.setClassName(GeckoAccessibility.class.getName());
- accEvent.setPackageName(GeckoAppShell.getContext().getPackageName());
- populateEventFromJSON(accEvent, message);
- AccessibilityManager accessibilityManager =
- (AccessibilityManager) GeckoAppShell.getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
- try {
- accessibilityManager.sendAccessibilityEvent(accEvent);
- } catch (IllegalStateException e) {
- // Accessibility is off.
- }
- }
-
- public static void sendAccessibilityEvent (final JSONObject message) {
- if (!sEnabled)
- return;
-
- final int eventType = message.optInt("eventType", -1);
- if (eventType < 0) {
- Log.e(LOGTAG, "No accessibility event type provided");
- return;
- }
-
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
- // Before Jelly Bean we send events directly from here while spoofing the source by setting
- // the package and class name manually.
- ThreadUtils.postToBackgroundThread(new Runnable() {
- @Override
- public void run() {
- sendDirectAccessibilityEvent(eventType, message);
- }
- });
- } else {
- // In Jelly Bean we populate an AccessibilityNodeInfo with the minimal amount of data to have
- // it work with TalkBack.
- final LayerView view = GeckoAppShell.getLayerView();
- if (view == null)
- return;
-
- if (sVirtualCursorNode == null)
- sVirtualCursorNode = AccessibilityNodeInfo.obtain(view, VIRTUAL_CURSOR_POSITION);
- sVirtualCursorNode.setEnabled(message.optBoolean("enabled", true));
- sVirtualCursorNode.setClickable(message.optBoolean("clickable"));
- sVirtualCursorNode.setCheckable(message.optBoolean("checkable"));
- sVirtualCursorNode.setChecked(message.optBoolean("checked"));
- sVirtualCursorNode.setPassword(message.optBoolean("password"));
-
- final JSONArray textArray = message.optJSONArray("text");
- StringBuilder sb = new StringBuilder();
- if (textArray != null && textArray.length() > 0) {
- sb.append(textArray.optString(0));
- for (int i = 1; i < textArray.length(); i++) {
- sb.append(" ").append(textArray.optString(i));
- }
- }
- sVirtualCursorNode.setText(sb.toString());
- sVirtualCursorNode.setContentDescription(message.optString("description"));
-
- JSONObject bounds = message.optJSONObject("bounds");
- if (bounds != null) {
- Rect relativeBounds = new Rect(bounds.optInt("left"), bounds.optInt("top"),
- bounds.optInt("right"), bounds.optInt("bottom"));
- sVirtualCursorNode.setBoundsInParent(relativeBounds);
- int[] locationOnScreen = new int[2];
- view.getLocationOnScreen(locationOnScreen);
- Rect screenBounds = new Rect(relativeBounds);
- screenBounds.offset(locationOnScreen[0], locationOnScreen[1]);
- sVirtualCursorNode.setBoundsInScreen(screenBounds);
- }
-
- final String brailleText = message.optString("brailleText");
- if (!brailleText.isEmpty()) {
- sendBrailleText(view, brailleText);
- }
-
- ThreadUtils.postToUiThread(new Runnable() {
- @Override
- public void run() {
- // If this is an accessibility focus, a lot of internal voodoo happens so we perform an
- // accessibility focus action on the view, and it in turn sends the right events.
- switch (eventType) {
- case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED:
- sEventMessage = message;
- view.performAccessibilityAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
- break;
- case AccessibilityEvent.TYPE_ANNOUNCEMENT:
- case AccessibilityEvent.TYPE_VIEW_SCROLLED:
- sEventMessage = null;
- final AccessibilityEvent accEvent = AccessibilityEvent.obtain(eventType);
- view.onInitializeAccessibilityEvent(accEvent);
- populateEventFromJSON(accEvent, message);
- view.getParent().requestSendAccessibilityEvent(view, accEvent);
- break;
- default:
- sEventMessage = message;
- view.sendAccessibilityEvent(eventType);
- break;
- }
- }
- });
-
- }
- }
-
- private static void sendBrailleText(final View view, final String text) {
- AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(view, VIRTUAL_CURSOR_POSITION);
- WriteData data = WriteData.forInfo(info);
- data.setText(text);
- // Set the focus blink
- data.setSelectionStart(0);
- data.setSelectionEnd(0);
- sSelfBrailleClient.write(data);
- }
-
- public static void setDelegate(LayerView layerview) {
- // Only use this delegate in Jelly Bean.
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
- layerview.setAccessibilityDelegate(new GeckoAccessibilityDelegate());
- layerview.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
- }
- }
-
- public static void onLayerViewFocusChanged(LayerView layerview, boolean gainFocus) {
- if (sEnabled)
- GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Accessibility:Focus",
- gainFocus ? "true" : "false"));
- }
-
- public static class GeckoAccessibilityDelegate extends View.AccessibilityDelegate {
- AccessibilityNodeProvider mAccessibilityNodeProvider;
-
- @Override
- public void onPopulateAccessibilityEvent (View host, AccessibilityEvent event) {
- super.onPopulateAccessibilityEvent(host, event);
- if (sEventMessage != null) {
- populateEventFromJSON(event, sEventMessage);
- // No matter where the a11y focus is requested, we always force it back to the current vc position.
- event.setSource(host, VIRTUAL_CURSOR_POSITION);
- }
- // We save the hover enter event so that we could reuse it for a subsequent accessibility focus event.
- if (event.getEventType() != AccessibilityEvent.TYPE_VIEW_HOVER_ENTER)
- sEventMessage = null;
- }
-
- @Override
- public AccessibilityNodeProvider getAccessibilityNodeProvider(final View host) {
- if (mAccessibilityNodeProvider == null)
- // The accessibility node structure for web content consists of 3 LayerView child nodes:
- // 1. VIRTUAL_CURSOR_PREVIOUS: Represents the virtual cursor position that is previous to the
- // current one.
- // 2. VIRTUAL_CURSOR_POSITION: Represents the current position of the virtual cursor.
- // 3. VIRTUAL_CURSOR_NEXT: Represents the next virtual cursor position.
- mAccessibilityNodeProvider = new AccessibilityNodeProvider() {
- @Override
- public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualDescendantId) {
- AccessibilityNodeInfo info = (virtualDescendantId == VIRTUAL_CURSOR_POSITION && sVirtualCursorNode != null) ?
- AccessibilityNodeInfo.obtain(sVirtualCursorNode) :
- AccessibilityNodeInfo.obtain(host, virtualDescendantId);
-
- switch (virtualDescendantId) {
- case View.NO_ID:
- // This is the parent LayerView node, populate it with children.
- onInitializeAccessibilityNodeInfo(host, info);
- info.addChild(host, VIRTUAL_CURSOR_PREVIOUS);
- info.addChild(host, VIRTUAL_CURSOR_POSITION);
- info.addChild(host, VIRTUAL_CURSOR_NEXT);
- break;
- default:
- info.setParent(host);
- info.setSource(host, virtualDescendantId);
- info.setVisibleToUser(true);
- info.setPackageName(GeckoAppShell.getContext().getPackageName());
- info.setClassName(host.getClass().getName());
- info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
- info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
- info.addAction(AccessibilityNodeInfo.ACTION_CLICK);
- info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY);
- info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY);
- info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER |
- AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD |
- AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
- break;
- }
- return info;
- }
-
- @Override
- public boolean performAction (int virtualViewId, int action, Bundle arguments) {
- if (action == AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS) {
- // The accessibility focus is permanently on the middle node, VIRTUAL_CURSOR_POSITION.
- // When accessibility focus is requested on one of its siblings we move the virtual cursor
- // either forward or backward depending on which sibling was selected.
-
- switch (virtualViewId) {
- case VIRTUAL_CURSOR_PREVIOUS:
- GeckoAppShell.
- sendEventToGecko(GeckoEvent.createBroadcastEvent("Accessibility:PreviousObject", null));
- return true;
- case VIRTUAL_CURSOR_NEXT:
- GeckoAppShell.
- sendEventToGecko(GeckoEvent.createBroadcastEvent("Accessibility:NextObject", null));
- return true;
- default:
- break;
- }
- } else if (action == AccessibilityNodeInfo.ACTION_CLICK && virtualViewId == VIRTUAL_CURSOR_POSITION) {
- GeckoAppShell.
- sendEventToGecko(GeckoEvent.createBroadcastEvent("Accessibility:ActivateObject", null));
- return true;
- } else if (action == AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY &&
- virtualViewId == VIRTUAL_CURSOR_POSITION) {
- // XXX: Self brailling gives this action with a bogus argument instead of an actual click action
- int granularity = arguments.getInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT);
- if (granularity < 0) {
- GeckoAppShell.
- sendEventToGecko(GeckoEvent.createBroadcastEvent("Accessibility:ActivateObject", null));
- } else {
- JSONObject movementData = new JSONObject();
- try {
- movementData.put("direction", "Next");
- movementData.put("granularity", granularity);
- } catch (JSONException e) {
- return true;
- }
- GeckoAppShell.
- sendEventToGecko(GeckoEvent.createBroadcastEvent("Accessibility:MoveCaret", movementData.toString()));
- }
- return true;
- } else if (action == AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY &&
- virtualViewId == VIRTUAL_CURSOR_POSITION) {
- JSONObject movementData = new JSONObject();
- try {
- movementData.put("direction", "Previous");
- movementData.put("granularity", arguments.getInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT));
- } catch (JSONException e) {
- return true;
- }
- GeckoAppShell.
- sendEventToGecko(GeckoEvent.createBroadcastEvent("Accessibility:MoveCaret", movementData.toString()));
- return true;
- }
- return host.performAccessibilityAction(action, arguments);
- }
- };
-
- return mAccessibilityNodeProvider;
- }
- }
-}
diff --git a/mobile/android/base/GeckoActivity.java b/mobile/android/base/GeckoActivity.java
deleted file mode 100644
index 762cde8e7..000000000
--- a/mobile/android/base/GeckoActivity.java
+++ /dev/null
@@ -1,100 +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/. */
-
-package org.mozilla.gecko;
-
-import android.content.ComponentName;
-import android.content.Intent;
-import android.support.v4.app.FragmentActivity;
-
-interface GeckoActivityStatus {
- public boolean isGeckoActivityOpened();
- public boolean isFinishing(); // typically from android.app.Activity
-};
-
-public class GeckoActivity extends FragmentActivity implements GeckoActivityStatus {
- // has this activity recently started another Gecko activity?
- private boolean mGeckoActivityOpened = false;
-
- @Override
- public void onPause() {
- super.onPause();
-
- if (getApplication() instanceof GeckoApplication) {
- ((GeckoApplication) getApplication()).onActivityPause(this);
- }
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- if (getApplication() instanceof GeckoApplication) {
- ((GeckoApplication) getApplication()).onActivityResume(this);
- mGeckoActivityOpened = false;
- }
- }
-
- @Override
- public void onCreate(android.os.Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- if (AppConstants.MOZ_ANDROID_ANR_REPORTER) {
- ANRReporter.register(getApplicationContext());
- }
- }
-
- @Override
- public void onDestroy() {
- if (AppConstants.MOZ_ANDROID_ANR_REPORTER) {
- ANRReporter.unregister();
- }
- super.onDestroy();
- }
-
- @Override
- public void startActivity(Intent intent) {
- mGeckoActivityOpened = checkIfGeckoActivity(intent);
- super.startActivity(intent);
- }
-
- @Override
- public void startActivityForResult(Intent intent, int request) {
- mGeckoActivityOpened = checkIfGeckoActivity(intent);
- super.startActivityForResult(intent, request);
- }
-
- private static boolean checkIfGeckoActivity(Intent intent) {
- // Whenever we call our own activity, the component and its package name is set.
- // If we call an activity from another package, or an open intent (leaving android to resolve)
- // component has a different package name or it is null.
- ComponentName component = intent.getComponent();
- return (component != null &&
- AppConstants.ANDROID_PACKAGE_NAME.equals(component.getPackageName()));
- }
-
- @Override
- public boolean isGeckoActivityOpened() {
- return mGeckoActivityOpened;
- }
-
- public boolean isApplicationInBackground() {
- return ((GeckoApplication) getApplication()).isApplicationInBackground();
- }
-
- @Override
- public void onLowMemory() {
- MemoryMonitor.getInstance().onLowMemory();
- super.onLowMemory();
- }
-
- @Override
- public void onTrimMemory(int level) {
- MemoryMonitor.getInstance().onTrimMemory(level);
- super.onTrimMemory(level);
- }
-
- public LightweightTheme getLightweightTheme() {
- return ((GeckoApplication) getApplication()).getLightweightTheme();
- }
-}
diff --git a/mobile/android/base/GeckoApp.java b/mobile/android/base/GeckoApp.java
deleted file mode 100644
index df436f5f8..000000000
--- a/mobile/android/base/GeckoApp.java
+++ /dev/null
@@ -1,2466 +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.gecko;
-
-import org.mozilla.gecko.DataReportingNotification;
-import org.mozilla.gecko.db.BrowserDB;
-import org.mozilla.gecko.gfx.BitmapUtils;
-import org.mozilla.gecko.gfx.Layer;
-import org.mozilla.gecko.gfx.LayerView;
-import org.mozilla.gecko.gfx.PluginLayer;
-import org.mozilla.gecko.menu.GeckoMenu;
-import org.mozilla.gecko.menu.GeckoMenuInflater;
-import org.mozilla.gecko.menu.MenuPanel;
-// import org.mozilla.gecko.health.BrowserHealthRecorder;
-// import org.mozilla.gecko.health.BrowserHealthRecorder.SessionInformation;
-import org.mozilla.gecko.updater.UpdateService;
-import org.mozilla.gecko.updater.UpdateServiceHelper;
-import org.mozilla.gecko.util.EventDispatcher;
-import org.mozilla.gecko.util.GeckoEventListener;
-import org.mozilla.gecko.util.GeckoEventResponder;
-import org.mozilla.gecko.util.HardwareUtils;
-import org.mozilla.gecko.util.ThreadUtils;
-import org.mozilla.gecko.util.UiAsyncTask;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.app.WallpaperManager;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.Configuration;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.hardware.Sensor;
-import android.hardware.SensorEvent;
-import android.hardware.SensorEventListener;
-import android.location.Location;
-import android.location.LocationListener;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.PowerManager;
-import android.os.StrictMode;
-import android.preference.PreferenceManager;
-import android.provider.ContactsContract;
-
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.util.Base64;
-import android.util.Log;
-import android.util.SparseBooleanArray;
-import android.view.Display;
-import android.view.Gravity;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.OrientationEventListener;
-import android.view.Surface;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-import android.view.TextureView;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.view.WindowManager;
-import android.widget.AbsoluteLayout;
-import android.widget.FrameLayout;
-import android.widget.ListView;
-import android.widget.RelativeLayout;
-import android.widget.SimpleAdapter;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import java.io.BufferedReader;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-abstract public class GeckoApp
- extends GeckoActivity
- implements GeckoEventListener, SensorEventListener, LocationListener,
- Tabs.OnTabsChangedListener, GeckoEventResponder,
- GeckoMenu.Callback, GeckoMenu.MenuPresenter,
- ContextGetter, GeckoAppShell.GeckoInterface
-{
- private static final String LOGTAG = "GeckoApp";
-
- private static enum StartupAction {
- NORMAL, /* normal application start */
- URL, /* launched with a passed URL */
- PREFETCH /* launched with a passed URL that we prefetch */
- }
-
- public static final String ACTION_ALERT_CALLBACK = "org.mozilla.gecko.ACTION_ALERT_CALLBACK";
- public static final String ACTION_WEBAPP_PREFIX = "org.mozilla.gecko.WEBAPP";
- public static final String ACTION_DEBUG = "org.mozilla.gecko.DEBUG";
- public static final String ACTION_BOOKMARK = "org.mozilla.gecko.BOOKMARK";
- public static final String ACTION_LOAD = "org.mozilla.gecko.LOAD";
- public static final String ACTION_LAUNCH_SETTINGS = "org.mozilla.gecko.SETTINGS";
- public static final String ACTION_INIT_PW = "org.mozilla.gecko.INIT_PW";
- public static final String SAVED_STATE_INTENT_HANDLED = "intentHandled";
- public static final String SAVED_STATE_IN_BACKGROUND = "inBackground";
- public static final String SAVED_STATE_PRIVATE_SESSION = "privateSession";
-
- public static final String PREFS_NAME = "GeckoApp";
- public static final String PREFS_OOM_EXCEPTION = "OOMException";
- public static final String PREFS_WAS_STOPPED = "wasStopped";
- public static final String PREFS_CRASHED = "crashed";
- public static final String PREFS_VERSION_CODE = "versionCode";
-
- static public final int RESTORE_NONE = 0;
- static public final int RESTORE_NORMAL = 1;
- static public final int RESTORE_CRASH = 2;
-
- protected RelativeLayout mMainLayout;
- protected RelativeLayout mGeckoLayout;
- public View getView() { return mGeckoLayout; }
- private View mCameraView;
- private OrientationEventListener mCameraOrientationEventListener;
- public List<GeckoAppShell.AppStateListener> mAppStateListeners;
- private static GeckoApp sAppContext;
- protected MenuPanel mMenuPanel;
- protected Menu mMenu;
- private static GeckoThread sGeckoThread;
- private GeckoProfile mProfile;
- public static int mOrientation;
- protected boolean mIsRestoringActivity;
- private boolean mIntentHandled;
- private String mCurrentResponse = "";
- public static boolean sIsUsingCustomProfile = false;
-
- private PromptService mPromptService;
- private TextSelection mTextSelection;
-
- protected DoorHangerPopup mDoorHangerPopup;
- protected FormAssistPopup mFormAssistPopup;
- protected TabsPanel mTabsPanel;
-
- // Handles notification messages from javascript
- protected NotificationHelper mNotificationHelper;
-
- protected LayerView mLayerView;
- private AbsoluteLayout mPluginContainer;
-
- private FullScreenHolder mFullScreenPluginContainer;
- private View mFullScreenPluginView;
-
- private HashMap<String, PowerManager.WakeLock> mWakeLocks = new HashMap<String, PowerManager.WakeLock>();
-
- protected int mRestoreMode = RESTORE_NONE;
- protected boolean mInitialized = false;
-
- private String mPrivateBrowsingSession;
-
-// private volatile BrowserHealthRecorder mHealthRecorder = null;
-
- abstract public int getLayout();
- abstract public boolean hasTabsSideBar();
- abstract protected String getDefaultProfileName();
-
- private static final String RESTARTER_ACTION = "org.mozilla.gecko.restart";
- private static final String RESTARTER_CLASS = "org.mozilla.gecko.Restarter";
-
- @SuppressWarnings("serial")
- class SessionRestoreException extends Exception {
- public SessionRestoreException(Exception e) {
- super(e);
- }
-
- public SessionRestoreException(String message) {
- super(message);
- }
- }
-
- void toggleChrome(final boolean aShow) { }
-
- void focusChrome() { }
-
- public Context getContext() {
- return sAppContext;
- }
-
- public Activity getActivity() {
- return this;
- }
-
- public LocationListener getLocationListener() {
- return this;
- }
-
- public SensorEventListener getSensorEventListener() {
- return this;
- }
-
- public static SharedPreferences getAppSharedPreferences() {
- return GeckoApp.sAppContext.getSharedPreferences(PREFS_NAME, 0);
- }
-
- public View getCameraView() {
- return mCameraView;
- }
-
- public void addAppStateListener(GeckoAppShell.AppStateListener listener) {
- mAppStateListeners.add(listener);
- }
-
- public void removeAppStateListener(GeckoAppShell.AppStateListener listener) {
- mAppStateListeners.remove(listener);
- }
-
- public FormAssistPopup getFormAssistPopup() {
- return mFormAssistPopup;
- }
-
- @Override
- public void onTabChanged(Tab tab, Tabs.TabEvents msg, Object data) {
- // When a tab is closed, it is always unselected first.
- // When a tab is unselected, another tab is always selected first.
- switch(msg) {
- case UNSELECTED:
- hidePlugins(tab);
- break;
-
- case LOCATION_CHANGE:
- // We only care about location change for the selected tab.
- if (!Tabs.getInstance().isSelectedTab(tab))
- break;
- // Fall through...
- case SELECTED:
- invalidateOptionsMenu();
- if (mFormAssistPopup != null)
- mFormAssistPopup.hide();
- break;
-
- case LOADED:
- // Sync up the layer view and the tab if the tab is
- // currently displayed.
- LayerView layerView = mLayerView;
- if (layerView != null && Tabs.getInstance().isSelectedTab(tab))
- layerView.setBackgroundColor(tab.getBackgroundColor());
- break;
-
- case DESKTOP_MODE_CHANGE:
- if (Tabs.getInstance().isSelectedTab(tab))
- invalidateOptionsMenu();
- break;
- }
- }
-
- public void refreshChrome() { }
-
- @Override
- public void invalidateOptionsMenu() {
- if (mMenu == null)
- return;
-
- onPrepareOptionsMenu(mMenu);
-
- if (Build.VERSION.SDK_INT >= 11)
- super.invalidateOptionsMenu();
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- mMenu = menu;
-
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.gecko_app_menu, mMenu);
- return true;
- }
-
- @Override
- public MenuInflater getMenuInflater() {
- if (Build.VERSION.SDK_INT >= 11)
- return new GeckoMenuInflater(this);
- else
- return super.getMenuInflater();
- }
-
- public MenuPanel getMenuPanel() {
- return mMenuPanel;
- }
-
- @Override
- public boolean onMenuItemSelected(MenuItem item) {
- return onOptionsItemSelected(item);
- }
-
- @Override
- public void openMenu() {
- openOptionsMenu();
- }
-
- @Override
- public void showMenu(View menu) {
- // Hide the menu only if we are showing the MenuPopup.
- if (!HardwareUtils.hasMenuButton())
- closeMenu();
-
- mMenuPanel.removeAllViews();
- mMenuPanel.addView(menu);
-
- openOptionsMenu();
- }
-
- @Override
- public void closeMenu() {
- closeOptionsMenu();
- }
-
- @Override
- public View onCreatePanelView(int featureId) {
- if (Build.VERSION.SDK_INT >= 11 && featureId == Window.FEATURE_OPTIONS_PANEL) {
- if (mMenuPanel == null) {
- mMenuPanel = new MenuPanel(this, null);
- } else {
- // Prepare the panel everytime before showing the menu.
- onPreparePanel(featureId, mMenuPanel, mMenu);
- }
-
- return mMenuPanel;
- }
-
- return super.onCreatePanelView(featureId);
- }
-
- @Override
- public boolean onCreatePanelMenu(int featureId, Menu menu) {
- if (Build.VERSION.SDK_INT >= 11 && featureId == Window.FEATURE_OPTIONS_PANEL) {
- if (mMenuPanel == null) {
- mMenuPanel = (MenuPanel) onCreatePanelView(featureId);
- }
-
- GeckoMenu gMenu = new GeckoMenu(this, null);
- gMenu.setCallback(this);
- gMenu.setMenuPresenter(this);
- menu = gMenu;
- mMenuPanel.addView(gMenu);
-
- return onCreateOptionsMenu(menu);
- }
-
- return super.onCreatePanelMenu(featureId, menu);
- }
-
- @Override
- public boolean onPreparePanel(int featureId, View view, Menu menu) {
- if (Build.VERSION.SDK_INT >= 11 && featureId == Window.FEATURE_OPTIONS_PANEL)
- return onPrepareOptionsMenu(menu);
-
- return super.onPreparePanel(featureId, view, menu);
- }
-
- @Override
- public boolean onMenuOpened(int featureId, Menu menu) {
- // exit full-screen mode whenever the menu is opened
- if (mLayerView != null && mLayerView.isFullScreen()) {
- GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("FullScreen:Exit", null));
- }
-
- if (Build.VERSION.SDK_INT >= 11 && featureId == Window.FEATURE_OPTIONS_PANEL) {
- if (mMenu == null) {
- onCreatePanelMenu(featureId, menu);
- onPreparePanel(featureId, mMenuPanel, mMenu);
- }
-
- // Scroll custom menu to the top
- if (mMenuPanel != null)
- mMenuPanel.scrollTo(0, 0);
-
- return true;
- }
-
- return super.onMenuOpened(featureId, menu);
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.quit:
- if (GeckoThread.checkAndSetLaunchState(GeckoThread.LaunchState.GeckoRunning, GeckoThread.LaunchState.GeckoExiting)) {
- GeckoAppShell.notifyGeckoOfEvent(GeckoEvent.createBroadcastEvent("Browser:Quit", null));
- } else {
- System.exit(0);
- }
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-
- @Override
- public void onOptionsMenuClosed(Menu menu) {
- if (Build.VERSION.SDK_INT >= 11) {
- mMenuPanel.removeAllViews();
- mMenuPanel.addView((GeckoMenu) mMenu);
- }
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- // Handle hardware menu key presses separately so that we can show a custom menu in some cases.
- if (keyCode == KeyEvent.KEYCODE_MENU) {
- openOptionsMenu();
- return true;
- }
-
- return super.onKeyDown(keyCode, event);
- }
-
- @Override
- protected void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
-
- if (outState == null)
- outState = new Bundle();
-
- outState.putBoolean(SAVED_STATE_IN_BACKGROUND, isApplicationInBackground());
- outState.putString(SAVED_STATE_PRIVATE_SESSION, mPrivateBrowsingSession);
-
- // Bug 896992 - Replace intent action with ACTION_MAIN on restart.
- if (mIntentHandled) {
- outState.putBoolean(SAVED_STATE_INTENT_HANDLED, true);
- }
- }
-
- void handleFaviconRequest(final String url) {
- (new UiAsyncTask<Void, Void, String>(ThreadUtils.getBackgroundHandler()) {
- @Override
- public String doInBackground(Void... params) {
- return Favicons.getInstance().getFaviconUrlForPageUrl(url);
- }
-
- @Override
- public void onPostExecute(String faviconUrl) {
- JSONObject args = new JSONObject();
-
- if (faviconUrl != null) {
- try {
- args.put("url", url);
- args.put("faviconUrl", faviconUrl);
- } catch (JSONException e) {
- Log.w(LOGTAG, "Error building JSON favicon arguments.", e);
- }
- }
-
- GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Reader:FaviconReturn", args.toString()));
- }
- }).execute();
- }
-
- void handleClearHistory() {
- BrowserDB.clearHistory(getContentResolver());
- }
-
- public void addTab() { }
-
- public void addPrivateTab() { }
-
- public void showNormalTabs() { }
-
- public void showPrivateTabs() { }
-
- public void showRemoteTabs() { }
-
- private void showTabs(TabsPanel.Panel panel) { }
-
- public void hideTabs() { }
-
- /**
- * Close the tab UI indirectly (not as the result of a direct user
- * action). This does not force the UI to close; for example in Firefox
- * tablet mode it will remain open unless the user explicitly closes it.
- *
- * @return True if the tab UI was hidden.
- */
- public boolean autoHideTabs() { return false; }
-
- public boolean areTabsShown() { return false; }
-
- @Override
- public void handleMessage(String event, JSONObject message) {
- try {
- if (event.equals("Toast:Show")) {
- final String msg = message.getString("message");
- final String duration = message.getString("duration");
- handleShowToast(msg, duration);
- } else if (event.equals("log")) {
- // generic log listener
- final String msg = message.getString("msg");
- Log.d(LOGTAG, "Log: " + msg);
- } else if (event.equals("Reader:FaviconRequest")) {
- final String url = message.getString("url");
- handleFaviconRequest(url);
- } else if (event.equals("Reader:GoToReadingList")) {
- showReadingList();
- } else if (event.equals("Gecko:Ready")) {
- geckoConnected();
- } else if (event.equals("ToggleChrome:Hide")) {
- toggleChrome(false);
- } else if (event.equals("ToggleChrome:Show")) {
- toggleChrome(true);
- } else if (event.equals("ToggleChrome:Focus")) {
- focusChrome();
- } else if (event.equals("DOMFullScreen:Start")) {
- // Local ref to layerView for thread safety
- LayerView layerView = mLayerView;
- if (layerView != null) {
- layerView.setFullScreen(true);
- }
- } else if (event.equals("DOMFullScreen:Stop")) {
- // Local ref to layerView for thread safety
- LayerView layerView = mLayerView;
- if (layerView != null) {
- layerView.setFullScreen(false);
- }
- } else if (event.equals("Permissions:Data")) {
- String host = message.getString("host");
- JSONArray permissions = message.getJSONArray("permissions");
- showSiteSettingsDialog(host, permissions);
- } else if (event.equals("Tab:ViewportMetadata")) {
- int tabId = message.getInt("tabID");
- Tab tab = Tabs.getInstance().getTab(tabId);
- if (tab == null)
- return;
- tab.setZoomConstraints(new ZoomConstraints(message));
- tab.setIsRTL(message.getBoolean("isRTL"));
- // Sync up the layer view and the tab if the tab is currently displayed.
- LayerView layerView = mLayerView;
- if (layerView != null && Tabs.getInstance().isSelectedTab(tab)) {
- layerView.setZoomConstraints(tab.getZoomConstraints());
- layerView.setIsRTL(tab.getIsRTL());
- }
- } else if (event.equals("Session:StatePurged")) {
- onStatePurged();
- } else if (event.equals("Bookmark:Insert")) {
- final String url = message.getString("url");
- final String title = message.getString("title");
- final Context context = this;
- ThreadUtils.postToUiThread(new Runnable() {
- @Override
- public void run() {
- Toast.makeText(context, R.string.bookmark_added, Toast.LENGTH_SHORT).show();
- ThreadUtils.postToBackgroundThread(new Runnable() {
- @Override
- public void run() {
- BrowserDB.addBookmark(getContentResolver(), title, url);
- }
- });
- }
- });
- } else if (event.equals("Accessibility:Event")) {
- GeckoAccessibility.sendAccessibilityEvent(message);
- } else if (event.equals("Accessibility:Ready")) {
- GeckoAccessibility.updateAccessibilitySettings(this);
- } else if (event.equals("Shortcut:Remove")) {
- final String url = message.getString("url");
- final String origin = message.getString("origin");
- final String title = message.getString("title");
- final String type = message.getString("shortcutType");
- GeckoAppShell.removeShortcut(title, url, origin, type);
- } else if (event.equals("WebApps:Open")) {
- String manifestURL = message.getString("manifestURL");
- String origin = message.getString("origin");
- Intent intent = GeckoAppShell.getWebAppIntent(manifestURL, origin, "", null);
- if (intent == null)
- return;
- startActivity(intent);
- } else if (event.equals("WebApps:Install")) {
- String name = message.getString("name");
- String manifestURL = message.getString("manifestURL");
- String iconURL = message.getString("iconURL");
- String origin = message.getString("origin");
- // preInstallWebapp will return a File object pointing to the profile directory of the webapp
- mCurrentResponse = GeckoAppShell.preInstallWebApp(name, manifestURL, origin).toString();
- GeckoAppShell.postInstallWebApp(name, manifestURL, origin, iconURL);
- } else if (event.equals("WebApps:PreInstall")) {
- String name = message.getString("name");
- String manifestURL = message.getString("manifestURL");
- String origin = message.getString("origin");
- // preInstallWebapp will return a File object pointing to the profile directory of the webapp
- mCurrentResponse = GeckoAppShell.preInstallWebApp(name, manifestURL, origin).toString();
- } else if (event.equals("WebApps:PostInstall")) {
- String name = message.getString("name");
- String manifestURL = message.getString("manifestURL");
- String iconURL = message.getString("iconURL");
- String origin = message.getString("origin");
- GeckoAppShell.postInstallWebApp(name, manifestURL, origin, iconURL);
- } else if (event.equals("WebApps:Uninstall")) {
- String origin = message.getString("origin");
- GeckoAppShell.uninstallWebApp(origin);
- } else if (event.equals("Share:Text")) {
- String text = message.getString("text");
- GeckoAppShell.openUriExternal(text, "text/plain", "", "", Intent.ACTION_SEND, "");
- } else if (event.equals("Share:Image")) {
- String src = message.getString("url");
- String type = message.getString("mime");
- GeckoAppShell.shareImage(src, type);
- } else if (event.equals("Wallpaper:Set")) {
- String src = message.getString("url");
- setImageAsWallpaper(src);
- } else if (event.equals("Sanitize:ClearHistory")) {
- handleClearHistory();
- } else if (event.equals("Update:Check")) {
- startService(new Intent(UpdateServiceHelper.ACTION_CHECK_FOR_UPDATE, null, this, UpdateService.class));
- } else if (event.equals("Update:Download")) {
- startService(new Intent(UpdateServiceHelper.ACTION_DOWNLOAD_UPDATE, null, this, UpdateService.class));
- } else if (event.equals("Update:Install")) {
- startService(new Intent(UpdateServiceHelper.ACTION_APPLY_UPDATE, null, this, UpdateService.class));
- } else if (event.equals("PrivateBrowsing:Data")) {
- // null strings return "null" (http://code.google.com/p/android/issues/detail?id=13830)
- if (message.isNull("session")) {
- mPrivateBrowsingSession = null;
- } else {
- mPrivateBrowsingSession = message.getString("session");
- }
- } else if (event.equals("Contact:Add")) {
- if (!message.isNull("email")) {
- Uri contactUri = Uri.parse(message.getString("email"));
- Intent i = new Intent(ContactsContract.Intents.SHOW_OR_CREATE_CONTACT, contactUri);
- startActivity(i);
- } else if (!message.isNull("phone")) {
- Uri contactUri = Uri.parse(message.getString("phone"));
- Intent i = new Intent(ContactsContract.Intents.SHOW_OR_CREATE_CONTACT, contactUri);
- startActivity(i);
- } else {
- // something went wrong.
- Log.e(LOGTAG, "Received Contact:Add message with no email nor phone number");
- }
- }
- } catch (Exception e) {
- Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
- }
- }
-
- public String getResponse(JSONObject origMessage) {
- String res = mCurrentResponse;
- mCurrentResponse = "";
- return res;
- }
-
- void onStatePurged() { }
-
- /**
- * @param aPermissions
- * Array of JSON objects to represent site permissions.
- * Example: { type: "offline-app", setting: "Store Offline Data", value: "Allow" }
- */
- private void showSiteSettingsDialog(String aHost, JSONArray aPermissions) {
- final AlertDialog.Builder builder = new AlertDialog.Builder(this);
-
- View customTitleView = getLayoutInflater().inflate(R.layout.site_setting_title, null);
- ((TextView) customTitleView.findViewById(R.id.title)).setText(R.string.site_settings_title);
- ((TextView) customTitleView.findViewById(R.id.host)).setText(aHost);
- builder.setCustomTitle(customTitleView);
-
- // If there are no permissions to clear, show the user a message about that.
- // In the future, we want to disable the menu item if there are no permissions to clear.
- if (aPermissions.length() == 0) {
- builder.setMessage(R.string.site_settings_no_settings);
- } else {
-
- ArrayList <HashMap<String, String>> itemList = new ArrayList <HashMap<String, String>>();
- for (int i = 0; i < aPermissions.length(); i++) {
- try {
- JSONObject permObj = aPermissions.getJSONObject(i);
- HashMap<String, String> map = new HashMap<String, String>();
- map.put("setting", permObj.getString("setting"));
- map.put("value", permObj.getString("value"));
- itemList.add(map);
- } catch (JSONException e) {
- Log.w(LOGTAG, "Exception populating settings items.", e);
- }
- }
-
- // setMultiChoiceItems doesn't support using an adapter, so we're creating a hack with
- // setSingleChoiceItems and changing the choiceMode below when we create the dialog
- builder.setSingleChoiceItems(new SimpleAdapter(
- GeckoApp.this,
- itemList,
- R.layout.site_setting_item,
- new String[] { "setting", "value" },
- new int[] { R.id.setting, R.id.value }
- ), -1, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) { }
- });
-
- builder.setPositiveButton(R.string.site_settings_clear, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- ListView listView = ((AlertDialog) dialog).getListView();
- SparseBooleanArray checkedItemPositions = listView.getCheckedItemPositions();
-
- // An array of the indices of the permissions we want to clear
- JSONArray permissionsToClear = new JSONArray();
- for (int i = 0; i < checkedItemPositions.size(); i++)
- if (checkedItemPositions.get(i))
- permissionsToClear.put(i);
-
- GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent(
- "Permissions:Clear", permissionsToClear.toString()));
- }
- });
- }
-
- builder.setNegativeButton(R.string.site_settings_cancel, new DialogInterface.OnClickListener(){
- @Override
- public void onClick(DialogInterface dialog, int id) {
- dialog.cancel();
- }
- });
-
- ThreadUtils.postToUiThread(new Runnable() {
- @Override
- public void run() {
- Dialog dialog = builder.create();
- dialog.show();
-
- ListView listView = ((AlertDialog) dialog).getListView();
- if (listView != null) {
- listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
- int listSize = listView.getAdapter().getCount();
- for (int i = 0; i < listSize; i++)
- listView.setItemChecked(i, true);
- }
- }
- });
- }
-
- public void showToast(final int resId, final int duration) {
- ThreadUtils.postToUiThread(new Runnable() {
- @Override
- public void run() {
- Toast.makeText(GeckoApp.this, resId, duration).show();
- }
- });
- }
-
- void handleShowToast(final String message, final String duration) {
- ThreadUtils.postToUiThread(new Runnable() {
- @Override
- public void run() {
- Toast toast;
- if (duration.equals("long"))
- toast = Toast.makeText(GeckoApp.this, message, Toast.LENGTH_LONG);
- else
- toast = Toast.makeText(GeckoApp.this, message, Toast.LENGTH_SHORT);
- toast.show();
- }
- });
- }
-
- private void addFullScreenPluginView(View view) {
- if (mFullScreenPluginView != null) {
- Log.w(LOGTAG, "Already have a fullscreen plugin view");
- return;
- }
-
- setFullScreen(true);
-
- view.setWillNotDraw(false);
- if (view instanceof SurfaceView) {
- ((SurfaceView) view).setZOrderOnTop(true);
- }
-
- mFullScreenPluginContainer = new FullScreenHolder(this);
-
- FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
- ViewGroup.LayoutParams.FILL_PARENT,
- ViewGroup.LayoutParams.FILL_PARENT,
- Gravity.CENTER);
- mFullScreenPluginContainer.addView(view, layoutParams);
-
-
- FrameLayout decor = (FrameLayout)getWindow().getDecorView();
- decor.addView(mFullScreenPluginContainer, layoutParams);
-
- mFullScreenPluginView = view;
- }
-
- public void addPluginView(final View view, final Rect rect, final boolean isFullScreen) {
- ThreadUtils.postToUiThread(new Runnable() {
- @Override
- public void run() {
- Tabs tabs = Tabs.getInstance();
- Tab tab = tabs.getSelectedTab();
-
- if (isFullScreen) {
- addFullScreenPluginView(view);
- return;
- }
-
- PluginLayer layer = (PluginLayer) tab.getPluginLayer(view);
- if (layer == null) {
- layer = new PluginLayer(view, rect, mLayerView.getRenderer().getMaxTextureSize());
- tab.addPluginLayer(view, layer);
- } else {
- layer.reset(rect);
- layer.setVisible(true);
- }
-
- mLayerView.addLayer(layer);
- }
- });
- }
-
- private void removeFullScreenPluginView(View view) {
- if (mFullScreenPluginView == null) {
- Log.w(LOGTAG, "Don't have a fullscreen plugin view");
- return;
- }
-
- if (mFullScreenPluginView != view) {
- Log.w(LOGTAG, "Passed view is not the current full screen view");
- return;
- }
-
- mFullScreenPluginContainer.removeView(mFullScreenPluginView);
-
- // We need do do this on the next iteration in order to avoid
- // a deadlock, see comment below in FullScreenHolder
- ThreadUtils.postToUiThread(new Runnable() {
- @Override
- public void run() {
- mLayerView.show();
- }
- });
-
- FrameLayout decor = (FrameLayout)getWindow().getDecorView();
- decor.removeView(mFullScreenPluginContainer);
-
- mFullScreenPluginView = null;
-
- GeckoScreenOrientationListener.getInstance().unlockScreenOrientation();
- setFullScreen(false);
- }
-
- public void removePluginView(final View view, final boolean isFullScreen) {
- ThreadUtils.postToUiThread(new Runnable() {
- @Override
- public void run() {
- Tabs tabs = Tabs.getInstance();
- Tab tab = tabs.getSelectedTab();
-
- if (isFullScreen) {
- removeFullScreenPluginView(view);
- return;
- }
-
- PluginLayer layer = (PluginLayer) tab.removePluginLayer(view);
- if (layer != null) {
- layer.destroy();
- }
- }
- });
- }
-
- private void setImageAsWallpaper(final String aSrc) {
- final String progText = getString(R.string.wallpaper_progress);
- final String successText = getString(R.string.wallpaper_success);
- final String failureText = getString(R.string.wallpaper_fail);
- final String fileName = aSrc.substring(aSrc.lastIndexOf("/") + 1);
- final PendingIntent emptyIntent = PendingIntent.getActivity(this, 0, new Intent(), 0);
- final AlertNotification notification = new AlertNotification(this, fileName.hashCode(),
- R.drawable.alert_download, fileName, progText, System.currentTimeMillis(), null);
- notification.setLatestEventInfo(this, fileName, progText, emptyIntent );
- notification.flags |= Notification.FLAG_ONGOING_EVENT;
- notification.show();
- new UiAsyncTask<Void, Void, Boolean>(ThreadUtils.getBackgroundHandler()) {
-
- @Override
- protected Boolean doInBackground(Void... params) {
- WallpaperManager mgr = WallpaperManager.getInstance(GeckoApp.this);
- if (mgr == null) {
- return false;
- }
-
- // Determine the ideal width and height of the wallpaper
- // for the device
-
- int idealWidth = mgr.getDesiredMinimumWidth();
- int idealHeight = mgr.getDesiredMinimumHeight();
-
- // Sometimes WallpaperManager's getDesiredMinimum*() methods
- // can return 0 if a Remote Exception occurs when calling the
- // Wallpaper Service. So if that fails, we are calculating
- // the ideal width and height from the device's display
- // resolution (excluding the decorated area)
-
- if (idealWidth <= 0 || idealHeight <= 0) {
- int orientation;
- Display defaultDisplay = getWindowManager().getDefaultDisplay();
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {
- orientation = defaultDisplay.getRotation();
- } else {
- orientation = defaultDisplay.getOrientation();
- }
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
- Point size = new Point();
- defaultDisplay.getSize(size);
- // The ideal wallpaper width is always twice the size of
- // display width
- if (orientation == Surface.ROTATION_0 || orientation == Surface.ROTATION_270) {
- idealWidth = size.x * 2;
- idealHeight = size.y;
- } else {
- idealWidth = size.y;
- idealHeight = size.x * 2;
- }
- } else {
- if (orientation == Surface.ROTATION_0 || orientation == Surface.ROTATION_270) {
- idealWidth = defaultDisplay.getWidth() * 2;
- idealHeight = defaultDisplay.getHeight();
- } else {
- idealWidth = defaultDisplay.getHeight();
- idealHeight = defaultDisplay.getWidth() * 2;
- }
- }
- }
-
- boolean isDataURI = aSrc.startsWith("data:");
- BitmapFactory.Options options = new BitmapFactory.Options();
- options.inJustDecodeBounds = true;
- Bitmap image = null;
- InputStream is = null;
- ByteArrayOutputStream os = null;
- try{
- if (isDataURI) {
- int dataStart = aSrc.indexOf(',');
- byte[] buf = Base64.decode(aSrc.substring(dataStart+1), Base64.DEFAULT);
- BitmapUtils.decodeByteArray(buf, options);
- options.inSampleSize = getBitmapSampleSize(options, idealWidth, idealHeight);
- options.inJustDecodeBounds = false;
- image = BitmapUtils.decodeByteArray(buf, options);
- } else {
- int byteRead;
- byte[] buf = new byte[4192];
- os = new ByteArrayOutputStream();
- URL url = new URL(aSrc);
- is = url.openStream();
-
- // Cannot read from same stream twice. Also, InputStream from
- // URL does not support reset. So converting to byte array
-
- while((byteRead = is.read(buf)) != -1) {
- os.write(buf, 0, byteRead);
- }
- byte[] imgBuffer = os.toByteArray();
- BitmapUtils.decodeByteArray(imgBuffer, options);
- options.inSampleSize = getBitmapSampleSize(options, idealWidth, idealHeight);
- options.inJustDecodeBounds = false;
- image = BitmapUtils.decodeByteArray(imgBuffer, options);
- }
- if(image != null) {
- mgr.setBitmap(image);
- return true;
- } else {
- return false;
- }
- } catch(OutOfMemoryError ome) {
- Log.e(LOGTAG, "Out of Memory when converting to byte array", ome);
- return false;
- } catch(IOException ioe) {
- Log.e(LOGTAG, "I/O Exception while setting wallpaper", ioe);
- return false;
- } finally {
- if(is != null) {
- try {
- is.close();
- } catch(IOException ioe) {
- Log.w(LOGTAG, "I/O Exception while closing stream", ioe);
- }
- }
- if(os != null) {
- try {
- os.close();
- } catch(IOException ioe) {
- Log.w(LOGTAG, "I/O Exception while closing stream", ioe);
- }
- }
- }
- }
-
- @Override
- protected void onPostExecute(Boolean success) {
- notification.cancel();
- notification.flags = 0;
- notification.flags |= Notification.FLAG_AUTO_CANCEL;
- if(!success) {
- notification.tickerText = failureText;
- notification.setLatestEventInfo(GeckoApp.this, fileName, failureText, emptyIntent);
- } else {
- notification.tickerText = successText;
- notification.setLatestEventInfo(GeckoApp.this, fileName, successText, emptyIntent);
- }
- notification.show();
- }
- }.execute();
- }
-
- private int getBitmapSampleSize(BitmapFactory.Options options, int idealWidth, int idealHeight) {
- int width = options.outWidth;
- int height = options.outHeight;
- int inSampleSize = 1;
- if (height > idealHeight || width > idealWidth) {
- if (width > height) {
- inSampleSize = Math.round((float)height / (float)idealHeight);
- } else {
- inSampleSize = Math.round((float)width / (float)idealWidth);
- }
- }
- return inSampleSize;
- }
-
- private void hidePluginLayer(Layer layer) {
- LayerView layerView = mLayerView;
- layerView.removeLayer(layer);
- layerView.requestRender();
- }
-
- private void showPluginLayer(Layer layer) {
- LayerView layerView = mLayerView;
- layerView.addLayer(layer);
- layerView.requestRender();
- }
-
- public void requestRender() {
- mLayerView.requestRender();
- }
-
- public void hidePlugins(Tab tab) {
- for (Layer layer : tab.getPluginLayers()) {
- if (layer instanceof PluginLayer) {
- ((PluginLayer) layer).setVisible(false);
- }
-
- hidePluginLayer(layer);
- }
-
- requestRender();
- }
-
- public void showPlugins() {
- Tabs tabs = Tabs.getInstance();
- Tab tab = tabs.getSelectedTab();
-
- showPlugins(tab);
- }
-
- public void showPlugins(Tab tab) {
- for (Layer layer : tab.getPluginLayers()) {
- showPluginLayer(layer);
-
- if (layer instanceof PluginLayer) {
- ((PluginLayer) layer).setVisible(true);
- }
- }
-
- requestRender();
- }
-
- public void setFullScreen(final boolean fullscreen) {
- ThreadUtils.postToUiThread(new Runnable() {
- @Override
- public void run() {
- // Hide/show the system notification bar
- Window window = getWindow();
- window.setFlags(fullscreen ?
- WindowManager.LayoutParams.FLAG_FULLSCREEN : 0,
- WindowManager.LayoutParams.FLAG_FULLSCREEN);
-
- if (Build.VERSION.SDK_INT >= 11)
- window.getDecorView().setSystemUiVisibility(fullscreen ? 1 : 0);
- }
- });
- }
-
- /**
- * Called when the activity is first created.
- *
- * Here we initialize all of our profile settings, Firefox Health Report,
- * and other one-shot constructions.
- **/
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- GeckoAppShell.registerGlobalExceptionHandler();
-
- // Enable Android Strict Mode for developers' local builds (the "default" channel).
- if ("default".equals(AppConstants.MOZ_UPDATE_CHANNEL)) {
- enableStrictMode();
- }
-
- String args = getIntent().getStringExtra("args");
-
- String profileName = null;
- String profilePath = null;
- if (args != null) {
- if (args.contains("-P")) {
- Pattern p = Pattern.compile("(?:-P\\s*)(\\w*)(\\s*)");
- Matcher m = p.matcher(args);
- if (m.find()) {
- profileName = m.group(1);
- }
- }
-
- if (args.contains("-profile")) {
- Pattern p = Pattern.compile("(?:-profile\\s*)(\\S*)(\\s*)");
- Matcher m = p.matcher(args);
- if (m.find()) {
- profilePath = m.group(1);
- }
- if (profileName == null) {
- profileName = getDefaultProfileName();
- if (profileName == null)
- profileName = "default";
- }
- GeckoApp.sIsUsingCustomProfile = true;
- }
-
- if (profileName != null || profilePath != null) {
- mProfile = GeckoProfile.get(this, profileName, profilePath);
- }
- }
-
- BrowserDB.initialize(getProfile().getName());
- ((GeckoApplication)getApplication()).initialize();
-
- sAppContext = this;
- GeckoAppShell.setContextGetter(this);
- GeckoAppShell.setGeckoInterface(this);
- ThreadUtils.setUiThread(Thread.currentThread(), new Handler());
-
- Tabs.getInstance().attachToActivity(this);
- Favicons.getInstance().attachToContext(this);
-
- // When we detect a locale change, we need to restart Gecko, which
- // actually means restarting the entire application. This logic should
- // actually be handled elsewhere since GeckoApp may not be alive to
- // handle this event if "Don't keep activities" is enabled (filed as
- // bug 889082).
- if (((GeckoApplication)getApplication()).needsRestart()) {
- doRestart();
- System.exit(0);
- return;
- }
-
- if (sGeckoThread != null) {
- // This happens when the GeckoApp activity is destroyed by Android
- // without killing the entire application (see Bug 769269).
- mIsRestoringActivity = true;
- }
-
- // Fix for Bug 830557 on Tegra boards running Froyo.
- // This fix must be done before doing layout.
- // Assume the bug is fixed in Gingerbread and up.
- if (Build.VERSION.SDK_INT < 9) {
- try {
- Class<?> inputBindResultClass =
- Class.forName("com.android.internal.view.InputBindResult");
- java.lang.reflect.Field creatorField =
- inputBindResultClass.getField("CREATOR");
- Log.i(LOGTAG, "froyo startup fix: " + String.valueOf(creatorField.get(null)));
- } catch (Exception e) {
- Log.w(LOGTAG, "froyo startup fix failed", e);
- }
- }
-
- LayoutInflater.from(this).setFactory(this);
-
- super.onCreate(savedInstanceState);
-
- mOrientation = getResources().getConfiguration().orientation;
-
- setContentView(getLayout());
-
- // Set up Gecko layout.
- mGeckoLayout = (RelativeLayout) findViewById(R.id.gecko_layout);
- mMainLayout = (RelativeLayout) findViewById(R.id.main_layout);
-
- // Set up tabs panel.
- mTabsPanel = (TabsPanel) findViewById(R.id.tabs_panel);
- mNotificationHelper = new NotificationHelper(this);
-
- // Check if the last run was exited due to a normal kill while
- // we were in the background, or a more harsh kill while we were
- // active.
- mRestoreMode = getSessionRestoreState(savedInstanceState);
- if (mRestoreMode == RESTORE_NORMAL && savedInstanceState != null) {
- boolean wasInBackground =
- savedInstanceState.getBoolean(SAVED_STATE_IN_BACKGROUND, false);
-
- if (savedInstanceState.getBoolean(SAVED_STATE_INTENT_HANDLED, false)) {
- Intent thisIntent = getIntent();
- // Bug 896992 - This intent has already been handled, clear the intent action.
- thisIntent.setAction(Intent.ACTION_MAIN);
- setIntent(thisIntent);
-
- // Persist this flag for reincarnations of this Activity Intent.
- mIntentHandled = true;
- }
-
- mPrivateBrowsingSession = savedInstanceState.getString(SAVED_STATE_PRIVATE_SESSION);
- }
-
- // Perform background initialization.
- ThreadUtils.postToBackgroundThread(new Runnable() {
- @Override
- public void run() {
- final SharedPreferences prefs = GeckoApp.getAppSharedPreferences();
-
-// SessionInformation previousSession = SessionInformation.fromSharedPrefs(prefs);
-
- SharedPreferences.Editor editor = prefs.edit();
- editor.putBoolean(GeckoApp.PREFS_OOM_EXCEPTION, false);
-
- // Put a flag to check if we got a normal `onSaveInstanceState`
- // on exit, or if we were suddenly killed (crash or native OOM).
- editor.putBoolean(GeckoApp.PREFS_WAS_STOPPED, false);
-
- editor.commit();
-
- // The lifecycle of mHealthRecorder is "shortly after onCreate"
- // through "onDestroy" -- essentially the same as the lifecycle
- // of the activity itself.
- final String profilePath = getProfile().getDir().getAbsolutePath();
- final EventDispatcher dispatcher = GeckoAppShell.getEventDispatcher();
-// Log.i(LOGTAG, "Creating BrowserHealthRecorder.");
-// mHealthRecorder = new BrowserHealthRecorder(GeckoApp.this, profilePath, dispatcher,
-// previousSession);
- }
- });
-
- GeckoAppShell.setNotificationClient(makeNotificationClient());
- }
-
- protected void initializeChrome() {
- mDoorHangerPopup = new DoorHangerPopup(this, null);
- mPluginContainer = (AbsoluteLayout) findViewById(R.id.plugin_container);
- mFormAssistPopup = (FormAssistPopup) findViewById(R.id.form_assist_popup);
-
- if (mCameraView == null) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
- mCameraView = new SurfaceView(this);
- ((SurfaceView)mCameraView).getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
- } else {
- mCameraView = new TextureView(this);
- }
- }
-
- if (mLayerView == null) {
- LayerView layerView = (LayerView) findViewById(R.id.layer_view);
- layerView.initializeView(GeckoAppShell.getEventDispatcher());
- mLayerView = layerView;
- GeckoAppShell.setLayerView(layerView);
- // bind the GeckoEditable instance to the new LayerView
- GeckoAppShell.notifyIMEContext(GeckoEditableListener.IME_STATE_DISABLED, "", "", "");
- }
- }
-
- /**
- * Loads the initial tab at Fennec startup.
- *
- * If Fennec was opened with an external URL, that URL will be loaded.
- * Otherwise, unless there was a session restore, the default URL
- * (about:home) be loaded.
- *
- * @param url External URL to load, or null to load the default URL
- */
- protected void loadStartupTab(String url) {
- if (url == null) {
- if (mRestoreMode == RESTORE_NONE) {
- // Show about:home if we aren't restoring previous session and
- // there's no external URL
- Tab tab = Tabs.getInstance().loadUrl("about:home", Tabs.LOADURL_NEW_TAB);
- }
- } else {
- // If given an external URL, load it
- int flags = Tabs.LOADURL_NEW_TAB | Tabs.LOADURL_USER_ENTERED | Tabs.LOADURL_EXTERNAL;
- Tabs.getInstance().loadUrl(url, flags);
- }
- }
-
- private void initialize() {
- mInitialized = true;
-
- invalidateOptionsMenu();
-
- Intent intent = getIntent();
- String action = intent.getAction();
-
- String passedUri = null;
- String uri = getURIFromIntent(intent);
- if (uri != null && uri.length() > 0) {
- passedUri = uri;
- }
-
- final boolean isExternalURL = passedUri != null && !passedUri.equals("about:home");
- StartupAction startupAction;
- if (isExternalURL) {
- startupAction = StartupAction.URL;
- } else {
- startupAction = StartupAction.NORMAL;
- }
-
- // Start migrating as early as possible, can do this in
- // parallel with Gecko load.
- checkMigrateProfile();
-
- Uri data = intent.getData();
- if (data != null && "http".equals(data.getScheme())) {
- startupAction = StartupAction.PREFETCH;
- ThreadUtils.postToBackgroundThread(new PrefetchRunnable(data.toString()));
- }
-
- Tabs.registerOnTabsChangedListener(this);
-
- initializeChrome();
-
- // If we are doing a restore, read the session data and send it to Gecko
- String restoreMessage = null;
- if (mRestoreMode != RESTORE_NONE && !mIsRestoringActivity) {
- try {
- // restoreSessionTabs() will create simple tab stubs with the
- // URL and title for each page, but we also need to restore
- // session history. restoreSessionTabs() will inject the IDs
- // of the tab stubs into the JSON data (which holds the session
- // history). This JSON data is then sent to Gecko so session
- // history can be restored for each tab.
- restoreMessage = restoreSessionTabs(isExternalURL);
- } catch (SessionRestoreException e) {
- // If restore failed, do a normal startup
- Log.e(LOGTAG, "An error occurred during restore", e);
- mRestoreMode = RESTORE_NONE;
- }
- }
-
- GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Session:Restore", restoreMessage));
-
- if (!mIsRestoringActivity) {
- loadStartupTab(isExternalURL ? passedUri : null);
- }
-
- if (mRestoreMode == RESTORE_NORMAL) {
- // If we successfully did an OOM restore, we now have tab stubs
- // from the last session. Any future tabs should be animated.
- Tabs.getInstance().notifyListeners(null, Tabs.TabEvents.RESTORED);
- } else {
- // Move the session file if it exists
- getProfile().moveSessionFile();
- }
-
- if (mRestoreMode == RESTORE_NONE) {
- Tabs.getInstance().notifyListeners(null, Tabs.TabEvents.RESTORED);
- }
-
- if (!mIsRestoringActivity) {
- sGeckoThread = new GeckoThread(intent, passedUri);
- ThreadUtils.setGeckoThread(sGeckoThread);
- }
- if (!ACTION_DEBUG.equals(action) &&
- GeckoThread.checkAndSetLaunchState(GeckoThread.LaunchState.Launching, GeckoThread.LaunchState.Launched)) {
- sGeckoThread.start();
- } else if (ACTION_DEBUG.equals(action) &&
- GeckoThread.checkAndSetLaunchState(GeckoThread.LaunchState.Launching, GeckoThread.LaunchState.WaitForDebugger)) {
- ThreadUtils.getUiHandler().postDelayed(new Runnable() {
- @Override
- public void run() {
- GeckoThread.setLaunchState(GeckoThread.LaunchState.Launching);
- sGeckoThread.start();
- }
- }, 1000 * 5 /* 5 seconds */);
- }
-
- // Check if launched from data reporting notification.
- if (ACTION_LAUNCH_SETTINGS.equals(action)) {
- mIntentHandled = true;
- Intent settingsIntent = new Intent(GeckoApp.this, GeckoPreferences.class);
- // Copy extras.
- settingsIntent.putExtras(intent);
- startActivity(settingsIntent);
- }
-
- //app state callbacks
- mAppStateListeners = new LinkedList<GeckoAppShell.AppStateListener>();
-
- //register for events
- registerEventListener("log");
- registerEventListener("Reader:ListCountRequest");
- registerEventListener("Reader:Added");
- registerEventListener("Reader:Removed");
- registerEventListener("Reader:Share");
- registerEventListener("Reader:FaviconRequest");
- registerEventListener("Reader:GoToReadingList");
- registerEventListener("onCameraCapture");
- registerEventListener("Menu:Add");
- registerEventListener("Menu:Remove");
- registerEventListener("Menu:Update");
- registerEventListener("Gecko:Ready");
- registerEventListener("Toast:Show");
- registerEventListener("DOMFullScreen:Start");
- registerEventListener("DOMFullScreen:Stop");
- registerEventListener("ToggleChrome:Hide");
- registerEventListener("ToggleChrome:Show");
- registerEventListener("ToggleChrome:Focus");
- registerEventListener("Permissions:Data");
- registerEventListener("Tab:ViewportMetadata");
- registerEventListener("Session:StatePurged");
- registerEventListener("Bookmark:Insert");
- registerEventListener("Accessibility:Event");
- registerEventListener("Accessibility:Ready");
- registerEventListener("Shortcut:Remove");
- registerEventListener("WebApps:Open");
- registerEventListener("WebApps:PreInstall");
- registerEventListener("WebApps:PostInstall");
- registerEventListener("WebApps:Install");
- registerEventListener("WebApps:Uninstall");
- registerEventListener("Share:Text");
- registerEventListener("Share:Image");
- registerEventListener("Wallpaper:Set");
- registerEventListener("Sanitize:ClearHistory");
- registerEventListener("Update:Check");
- registerEventListener("Update:Download");
- registerEventListener("Update:Install");
- registerEventListener("PrivateBrowsing:Data");
- registerEventListener("Contact:Add");
-
- if (SmsManager.getInstance() != null) {
- SmsManager.getInstance().start();
- }
-
- mPromptService = new PromptService(this);
-
- mTextSelection = new TextSelection((TextSelectionHandle) findViewById(R.id.start_handle),
- (TextSelectionHandle) findViewById(R.id.middle_handle),
- (TextSelectionHandle) findViewById(R.id.end_handle),
- GeckoAppShell.getEventDispatcher(),
- this);
-
- PrefsHelper.getPref("app.update.autodownload", new PrefsHelper.PrefHandlerBase() {
- @Override public void prefValue(String pref, String value) {
- UpdateServiceHelper.registerForUpdates(GeckoApp.this, value);
- }
- });
-
- ThreadUtils.getBackgroundHandler().postDelayed(new Runnable() {
- @Override
- public void run() {
- // Sync settings need Gecko to be loaded, so
- // no hurry in starting this.
- checkMigrateSync();
-
- // Kick off our background services that upload health reports.
- // We do this by invoking the broadcast receiver, which uses the
- // system alarm infrastructure to perform tasks at intervals.
- GeckoPreferences.broadcastHealthReportUploadPref(GeckoApp.this);
-
- /*
- XXXX see bug 635342
- We want to disable this code if possible. It is about 145ms in runtime
- SharedPreferences settings = getPreferences(Activity.MODE_PRIVATE);
- String localeCode = settings.getString(getPackageName() + ".locale", "");
- if (localeCode != null && localeCode.length() > 0)
- GeckoAppShell.setSelectedLocale(localeCode);
- */
-
- if (!GeckoThread.checkLaunchState(GeckoThread.LaunchState.Launched)) {
- return;
- }
- }
- }, 50);
-
- if (mIsRestoringActivity) {
- GeckoThread.setLaunchState(GeckoThread.LaunchState.GeckoRunning);
- Tab selectedTab = Tabs.getInstance().getSelectedTab();
- if (selectedTab != null)
- Tabs.getInstance().notifyListeners(selectedTab, Tabs.TabEvents.SELECTED);
- geckoConnected();
- GeckoAppShell.setLayerClient(mLayerView.getLayerClient());
- GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Viewport:Flush", null));
- }
-
- if (ACTION_ALERT_CALLBACK.equals(action)) {
- processAlertCallback(intent);
- }
- }
-
- private String restoreSessionTabs(final boolean isExternalURL) throws SessionRestoreException {
- try {
- String sessionString = getProfile().readSessionFile(false);
- if (sessionString == null) {
- throw new SessionRestoreException("Could not read from session file");
- }
-
- // If we are doing an OOM restore, parse the session data and
- // stub the restored tabs immediately. This allows the UI to be
- // updated before Gecko has restored.
- if (mRestoreMode == RESTORE_NORMAL) {
- final JSONArray tabs = new JSONArray();
- SessionParser parser = new SessionParser() {
- @Override
- public void onTabRead(SessionTab sessionTab) {
- JSONObject tabObject = sessionTab.getTabObject();
-
- int flags = Tabs.LOADURL_NEW_TAB;
- flags |= ((isExternalURL || !sessionTab.isSelected()) ? Tabs.LOADURL_DELAY_LOAD : 0);
- flags |= (tabObject.optBoolean("desktopMode") ? Tabs.LOADURL_DESKTOP : 0);
- flags |= (tabObject.optBoolean("isPrivate") ? Tabs.LOADURL_PRIVATE : 0);
-
- Tab tab = Tabs.getInstance().loadUrl(sessionTab.getUrl(), flags);
- tab.updateTitle(sessionTab.getTitle());
-
- try {
- tabObject.put("tabId", tab.getId());
- } catch (JSONException e) {
- Log.e(LOGTAG, "JSON error", e);
- }
- tabs.put(tabObject);
- }
- };
-
- if (mPrivateBrowsingSession == null) {
- parser.parse(sessionString);
- } else {
- parser.parse(sessionString, mPrivateBrowsingSession);
- }
-
- if (tabs.length() > 0) {
- sessionString = new JSONObject().put("windows", new JSONArray().put(new JSONObject().put("tabs", tabs))).toString();
- } else {
- throw new SessionRestoreException("No tabs could be read from session file");
- }
- }
-
- JSONObject restoreData = new JSONObject();
- restoreData.put("normalRestore", mRestoreMode == RESTORE_NORMAL);
- restoreData.put("sessionString", sessionString);
- return restoreData.toString();
-
- } catch (JSONException e) {
- throw new SessionRestoreException(e);
- }
- }
-
- public GeckoProfile getProfile() {
- // fall back to default profile if we didn't load a specific one
- if (mProfile == null) {
- mProfile = GeckoProfile.get(this);
- }
- return mProfile;
- }
-
- protected int getSessionRestoreState(Bundle savedInstanceState) {
- final SharedPreferences prefs = GeckoApp.getAppSharedPreferences();
- int restoreMode = RESTORE_NONE;
-
- // If the version has changed, the user has done an upgrade, so restore
- // previous tabs.
- final int versionCode = getVersionCode();
- if (prefs.getInt(PREFS_VERSION_CODE, 0) != versionCode) {
- ThreadUtils.postToBackgroundThread(new Runnable() {
- @Override
- public void run() {
- prefs.edit()
- .putInt(PREFS_VERSION_CODE, versionCode)
- .commit();
- }
- });
-
- restoreMode = RESTORE_NORMAL;
- }
-
- // We record crashes in the crash reporter. If sessionstore.js
- // exists, but we didn't flag a crash in the crash reporter, we
- // were probably just force killed by the user, so we shouldn't do
- // a restore...
- if (prefs.getBoolean(PREFS_CRASHED, false)) {
- ThreadUtils.postToBackgroundThread(new Runnable() {
- @Override
- public void run() {
- prefs.edit()
- .putBoolean(PREFS_CRASHED, false)
- .commit();
- }
- });
-
- restoreMode = RESTORE_CRASH;
- }
-
- // ...except for when the user chooses to.
- if (savedInstanceState != null ||
- PreferenceManager.getDefaultSharedPreferences(this).getBoolean(GeckoPreferences.PREFS_RESTORE_SESSION, false)) {
- restoreMode = RESTORE_NORMAL;
- }
-
- return restoreMode;
- }
-
- /**
- * Enable Android StrictMode checks (for supported OS versions).
- * http://developer.android.com/reference/android/os/StrictMode.html
- */
- private void enableStrictMode() {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD) {
- return;
- }
-
- Log.d(LOGTAG, "Enabling Android StrictMode");
-
- StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
- .detectAll()
- .penaltyLog()
- .build());
-
- StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
- .detectAll()
- .penaltyLog()
- .build());
- }
-
- public void enableCameraView() {
- // Start listening for orientation events
- mCameraOrientationEventListener = new OrientationEventListener(this) {
- @Override
- public void onOrientationChanged(int orientation) {
- if (mAppStateListeners != null) {
- for (GeckoAppShell.AppStateListener listener: mAppStateListeners) {
- listener.onOrientationChanged();
- }
- }
- }
- };
- mCameraOrientationEventListener.enable();
-
- // Try to make it fully transparent.
- if (mCameraView instanceof SurfaceView) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
- mCameraView.setAlpha(0.0f);
- }
- } else if (mCameraView instanceof TextureView) {
- mCameraView.setAlpha(0.0f);
- }
- RelativeLayout mCameraLayout = (RelativeLayout) findViewById(R.id.camera_layout);
- // Some phones (eg. nexus S) need at least a 8x16 preview size
- mCameraLayout.addView(mCameraView,
- new AbsoluteLayout.LayoutParams(8, 16, 0, 0));
- }
-
- public void disableCameraView() {
- if (mCameraOrientationEventListener != null) {
- mCameraOrientationEventListener.disable();
- mCameraOrientationEventListener = null;
- }
- RelativeLayout mCameraLayout = (RelativeLayout) findViewById(R.id.camera_layout);
- mCameraLayout.removeView(mCameraView);
- }
-
- public String getDefaultUAString() {
- return HardwareUtils.isTablet() ? AppConstants.USER_AGENT_FENNEC_TABLET :
- AppConstants.USER_AGENT_FENNEC_MOBILE;
- }
-
- public String getUAStringForHost(String host) {
- // With our standard UA String, we get a 200 response code and
- // client-side redirect from t.co. This bot-like UA gives us a
- // 301 response code
- if ("t.co".equals(host)) {
- return AppConstants.USER_AGENT_BOT_LIKE;
- }
- return getDefaultUAString();
- }
-
- class PrefetchRunnable implements Runnable {
- private String mPrefetchUrl;
-
- PrefetchRunnable(String prefetchUrl) {
- mPrefetchUrl = prefetchUrl;
- }
-
- @Override
- public void run() {
- HttpURLConnection connection = null;
- try {
- URL url = new URL(mPrefetchUrl);
- // data url should have an http scheme
- connection = (HttpURLConnection) url.openConnection();
- connection.setRequestProperty("User-Agent", getUAStringForHost(url.getHost()));
- connection.setInstanceFollowRedirects(false);
- connection.setRequestMethod("GET");
- connection.connect();
- } catch (Exception e) {
- Log.e(LOGTAG, "Exception prefetching URL", e);
- } finally {
- if (connection != null)
- connection.disconnect();
- }
- }
- }
-
- private void processAlertCallback(Intent intent) {
- String alertName = "";
- String alertCookie = "";
- Uri data = intent.getData();
- if (data != null) {
- alertName = data.getQueryParameter("name");
- if (alertName == null)
- alertName = "";
- alertCookie = data.getQueryParameter("cookie");
- if (alertCookie == null)
- alertCookie = "";
- }
- handleNotification(ACTION_ALERT_CALLBACK, alertName, alertCookie);
-
- if (intent.hasExtra(NotificationHelper.NOTIFICATION_ID)) {
- String id = intent.getStringExtra(NotificationHelper.NOTIFICATION_ID);
- mNotificationHelper.hideNotification(id);
- }
- }
-
- @Override
- protected void onNewIntent(Intent intent) {
- if (GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoExiting)) {
- // We're exiting and shouldn't try to do anything else just incase
- // we're hung for some reason we'll force the process to exit
- System.exit(0);
- return;
- }
-
- // if we were previously OOM killed, we can end up here when launching
- // from external shortcuts, so set this as the intent for initialization
- if (!mInitialized) {
- setIntent(intent);
- return;
- }
-
- // don't perform any actions if launching from recent apps
- if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0)
- return;
-
- final String action = intent.getAction();
-
- if (Intent.ACTION_MAIN.equals(action)) {
- GeckoAppShell.sendEventToGecko(GeckoEvent.createURILoadEvent(""));
- } else if (ACTION_LOAD.equals(action)) {
- String uri = intent.getDataString();
- Tabs.getInstance().loadUrl(uri);
- } else if (Intent.ACTION_VIEW.equals(action)) {
- String uri = intent.getDataString();
- GeckoAppShell.sendEventToGecko(GeckoEvent.createURILoadEvent(uri));
- } else if (action != null && action.startsWith(ACTION_WEBAPP_PREFIX)) {
- String uri = getURIFromIntent(intent);
- GeckoAppShell.sendEventToGecko(GeckoEvent.createWebappLoadEvent(uri));
- } else if (ACTION_BOOKMARK.equals(action)) {
- String uri = getURIFromIntent(intent);
- GeckoAppShell.sendEventToGecko(GeckoEvent.createBookmarkLoadEvent(uri));
- } else if (Intent.ACTION_SEARCH.equals(action)) {
- String uri = getURIFromIntent(intent);
- GeckoAppShell.sendEventToGecko(GeckoEvent.createURILoadEvent(uri));
- } else if (ACTION_ALERT_CALLBACK.equals(action)) {
- processAlertCallback(intent);
- } else if (ACTION_LAUNCH_SETTINGS.equals(action)) {
- mIntentHandled = true;
- // Check if launched from data reporting notification.
- Intent settingsIntent = new Intent(GeckoApp.this, GeckoPreferences.class);
- // Copy extras.
- settingsIntent.putExtras(intent);
- startActivity(settingsIntent);
- }
- }
-
- /*
- * Handles getting a uri from and intent in a way that is backwards
- * compatable with our previous implementations
- */
- protected String getURIFromIntent(Intent intent) {
- final String action = intent.getAction();
- if (ACTION_ALERT_CALLBACK.equals(action))
- return null;
-
- String uri = intent.getDataString();
- if (uri != null)
- return uri;
-
- if ((action != null && action.startsWith(ACTION_WEBAPP_PREFIX)) || ACTION_BOOKMARK.equals(action)) {
- uri = intent.getStringExtra("args");
- if (uri != null && uri.startsWith("--url=")) {
- uri.replace("--url=", "");
- }
- }
- return uri;
- }
-
- @Override
- public void onResume()
- {
- // After an onPause, the activity is back in the foreground.
- // Undo whatever we did in onPause.
- super.onResume();
-
- int newOrientation = getResources().getConfiguration().orientation;
-
- if (mOrientation != newOrientation) {
- mOrientation = newOrientation;
- refreshChrome();
- }
-
- GeckoScreenOrientationListener.getInstance().start();
-
- // User may have enabled/disabled accessibility.
- GeckoAccessibility.updateAccessibilitySettings(this);
-
- if (mAppStateListeners != null) {
- for (GeckoAppShell.AppStateListener listener: mAppStateListeners) {
- listener.onResume();
- }
- }
-
- // We use two times: a pseudo-unique wall-clock time to identify the
- // current session across power cycles, and the elapsed realtime to
- // track the duration of the session.
- final long now = System.currentTimeMillis();
- final long realTime = android.os.SystemClock.elapsedRealtime();
-
-/* ThreadUtils.postToBackgroundThread(new Runnable() {
- @Override
- public void run() {
- // Now construct the new session on BrowserHealthRecorder's behalf. We do this here
- // so it can benefit from a single near-startup prefs commit.
- SessionInformation currentSession = new SessionInformation(now, realTime);
-
- SharedPreferences prefs = GeckoApp.getAppSharedPreferences();
- SharedPreferences.Editor editor = prefs.edit();
- editor.putBoolean(GeckoApp.PREFS_WAS_STOPPED, false);
- currentSession.recordBegin(editor);
- editor.commit();
-
- final BrowserHealthRecorder rec = mHealthRecorder;
- if (rec != null) {
- rec.setCurrentSession(currentSession);
- } else {
- Log.w(LOGTAG, "Can't record session: rec is null.");
- }
- }
- }); */
- }
-
- @Override
- public void onWindowFocusChanged(boolean hasFocus) {
- super.onWindowFocusChanged(hasFocus);
-
- if (!mInitialized && hasFocus) {
- initialize();
- getWindow().setBackgroundDrawable(null);
- }
- }
-
- @Override
- public void onPause()
- {
- // final BrowserHealthRecorder rec = mHealthRecorder;
-
- // In some way it's sad that Android will trigger StrictMode warnings
- // here as the whole point is to save to disk while the activity is not
- // interacting with the user.
- /* ThreadUtils.postToBackgroundThread(new Runnable() {
- @Override
- public void run() {
- SharedPreferences prefs = GeckoApp.getAppSharedPreferences();
- SharedPreferences.Editor editor = prefs.edit();
- editor.putBoolean(GeckoApp.PREFS_WAS_STOPPED, true);
- if (rec != null) {
- rec.recordSessionEnd("P", editor);
- }
- editor.commit();
- }
- }); */
-
- GeckoScreenOrientationListener.getInstance().stop();
-
- if (mAppStateListeners != null) {
- for(GeckoAppShell.AppStateListener listener: mAppStateListeners) {
- listener.onPause();
- }
- }
-
- super.onPause();
- }
-
- @Override
- public void onRestart()
- {
- ThreadUtils.postToBackgroundThread(new Runnable() {
- @Override
- public void run() {
- SharedPreferences prefs = GeckoApp.getAppSharedPreferences();
- SharedPreferences.Editor editor = prefs.edit();
- editor.putBoolean(GeckoApp.PREFS_WAS_STOPPED, false);
- editor.commit();
- }
- });
-
- super.onRestart();
- }
-
- @Override
- public void onDestroy()
- {
- unregisterEventListener("log");
- unregisterEventListener("Reader:ListCountRequest");
- unregisterEventListener("Reader:Added");
- unregisterEventListener("Reader:Removed");
- unregisterEventListener("Reader:Share");
- unregisterEventListener("Reader:FaviconRequest");
- unregisterEventListener("Reader:GoToReadingList");
- unregisterEventListener("onCameraCapture");
- unregisterEventListener("Menu:Add");
- unregisterEventListener("Menu:Remove");
- unregisterEventListener("Menu:Update");
- unregisterEventListener("Gecko:Ready");
- unregisterEventListener("Toast:Show");
- unregisterEventListener("DOMFullScreen:Start");
- unregisterEventListener("DOMFullScreen:Stop");
- unregisterEventListener("ToggleChrome:Hide");
- unregisterEventListener("ToggleChrome:Show");
- unregisterEventListener("ToggleChrome:Focus");
- unregisterEventListener("Permissions:Data");
- unregisterEventListener("Tab:ViewportMetadata");
- unregisterEventListener("Session:StatePurged");
- unregisterEventListener("Bookmark:Insert");
- unregisterEventListener("Accessibility:Event");
- unregisterEventListener("Accessibility:Ready");
- unregisterEventListener("Shortcut:Remove");
- unregisterEventListener("WebApps:Open");
- unregisterEventListener("WebApps:PreInstall");
- unregisterEventListener("WebApps:PostInstall");
- unregisterEventListener("WebApps:Install");
- unregisterEventListener("WebApps:Uninstall");
- unregisterEventListener("Share:Text");
- unregisterEventListener("Share:Image");
- unregisterEventListener("Wallpaper:Set");
- unregisterEventListener("Sanitize:ClearHistory");
- unregisterEventListener("Update:Check");
- unregisterEventListener("Update:Download");
- unregisterEventListener("Update:Install");
- unregisterEventListener("PrivateBrowsing:Data");
- unregisterEventListener("Contact:Add");
-
- deleteTempFiles();
-
- if (mLayerView != null)
- mLayerView.destroy();
- if (mDoorHangerPopup != null)
- mDoorHangerPopup.destroy();
- if (mFormAssistPopup != null)
- mFormAssistPopup.destroy();
- if (mPromptService != null)
- mPromptService.destroy();
- if (mTextSelection != null)
- mTextSelection.destroy();
- if (mNotificationHelper != null)
- mNotificationHelper.destroy();
-
- Tabs.getInstance().detachFromActivity(this);
-
- if (SmsManager.getInstance() != null) {
- SmsManager.getInstance().stop();
- if (isFinishing())
- SmsManager.getInstance().shutdown();
- }
-
-/* final BrowserHealthRecorder rec = mHealthRecorder;
- mHealthRecorder = null;
- if (rec != null) {
- // Closing a BrowserHealthRecorder could incur a write.
- ThreadUtils.postToBackgroundThread(new Runnable() {
- @Override
- public void run() {
- rec.close();
- }
- });
- } */
-
- super.onDestroy();
-
- Tabs.unregisterOnTabsChangedListener(this);
- }
-
- protected void registerEventListener(String event) {
- GeckoAppShell.getEventDispatcher().registerEventListener(event, this);
- }
-
- protected void unregisterEventListener(String event) {
- GeckoAppShell.getEventDispatcher().unregisterEventListener(event, this);
- }
-
- // Get a temporary directory, may return null
- public static File getTempDirectory() {
- File dir = sAppContext.getExternalFilesDir("temp");
- return dir;
- }
-
- // Delete any files in our temporary directory
- public static void deleteTempFiles() {
- File dir = getTempDirectory();
- if (dir == null)
- return;
- File[] files = dir.listFiles();
- if (files == null)
- return;
- for (File file : files) {
- file.delete();
- }
- }
-
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
-
- if (mOrientation != newConfig.orientation) {
- mOrientation = newConfig.orientation;
- if (mFormAssistPopup != null)
- mFormAssistPopup.hide();
- refreshChrome();
- }
- }
-
- public String getContentProcessName() {
- return AppConstants.MOZ_CHILD_PROCESS_NAME;
- }
-
- /*
- * Only one factory can be set on the inflater; however, we want to use two
- * factories (GeckoViewsFactory and the FragmentActivity factory).
- * Overriding onCreateView() here allows us to dispatch view creation to
- * both factories.
- */
- @Override
- public View onCreateView(String name, Context context, AttributeSet attrs) {
- View view = GeckoViewsFactory.getInstance().onCreateView(name, context, attrs);
- if (view == null) {
- view = super.onCreateView(name, context, attrs);
- }
- return view;
- }
-
- public void addEnvToIntent(Intent intent) {
- Map<String,String> envMap = System.getenv();
- Set<Map.Entry<String,String>> envSet = envMap.entrySet();
- Iterator<Map.Entry<String,String>> envIter = envSet.iterator();
- int c = 0;
- while (envIter.hasNext()) {
- Map.Entry<String,String> entry = envIter.next();
- intent.putExtra("env" + c, entry.getKey() + "="
- + entry.getValue());
- c++;
- }
- }
-
- public void doRestart() {
- doRestart(RESTARTER_ACTION);
- }
-
- public void doRestart(String action) {
- Log.d(LOGTAG, "doRestart(\"" + action + "\")");
- try {
- Intent intent = new Intent(action);
- intent.setClassName(AppConstants.ANDROID_PACKAGE_NAME, RESTARTER_CLASS);
- /* TODO: addEnvToIntent(intent); */
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
- Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
- Log.d(LOGTAG, "Restart intent: " + intent.toString());
- GeckoAppShell.killAnyZombies();
- startActivity(intent);
- } catch (Exception e) {
- Log.e(LOGTAG, "Error effecting restart.", e);
- }
- finish();
- // Give the restart process time to start before we die
- GeckoAppShell.waitForAnotherGeckoProc();
- }
-
- public void handleNotification(String action, String alertName, String alertCookie) {
- // If Gecko isn't running yet, we ignore the notification. Note that
- // even if Gecko is running but it was restarted since the notification
- // was created, the notification won't be handled (bug 849653).
- if (GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoRunning)) {
- GeckoAppShell.handleNotification(action, alertName, alertCookie);
- }
- }
-
- private void checkMigrateProfile() {
- final File profileDir = getProfile().getDir();
-
- if (profileDir != null) {
- final GeckoApp app = GeckoApp.sAppContext;
-
- ThreadUtils.postToBackgroundThread(new Runnable() {
- @Override
- public void run() {
- ProfileMigrator profileMigrator = new ProfileMigrator(app);
-
- // Do a migration run on the first start after an upgrade.
- if (!GeckoApp.sIsUsingCustomProfile &&
- !profileMigrator.hasMigrationRun()) {
- // Show the "Setting up Fennec" screen if this takes
- // a while.
-
- // Create a "final" holder for the setup screen so that we can
- // create it in startCallback and still find a reference to it
- // in stopCallback. (We must create it on the UI thread to fix
- // bug 788216). Note that synchronization is not a problem here
- // since it is only ever touched on the UI thread.
- final SetupScreen[] setupScreenHolder = new SetupScreen[1];
-
- final Runnable startCallback = new Runnable() {
- @Override
- public void run() {
- ThreadUtils.postToUiThread(new Runnable() {
- @Override
- public void run() {
- setupScreenHolder[0] = new SetupScreen(app);
- setupScreenHolder[0].show();
- }
- });
- }
- };
-
- final Runnable stopCallback = new Runnable() {
- @Override
- public void run() {
- ThreadUtils.postToUiThread(new Runnable() {
- @Override
- public void run() {
- SetupScreen screen = setupScreenHolder[0];
- // screen will never be null if this code runs, but
- // stranger things have happened...
- if (screen != null) {
- screen.dismiss();
- }
- }
- });
- }
- };
-
- profileMigrator.setLongOperationCallbacks(startCallback,
- stopCallback);
- profileMigrator.launchPlaces(profileDir);
- finishProfileMigration();
- }
- }}
- );
- }
- }
-
- protected void finishProfileMigration() {
- }
-
- private void checkMigrateSync() {
- final File profileDir = getProfile().getDir();
- if (!GeckoApp.sIsUsingCustomProfile && profileDir != null) {
- final GeckoApp app = GeckoApp.sAppContext;
- ProfileMigrator profileMigrator = new ProfileMigrator(app);
- if (!profileMigrator.hasSyncMigrated()) {
- profileMigrator.launchSyncPrefs();
- }
- }
- }
-
- public PromptService getPromptService() {
- return mPromptService;
- }
-
- public void showReadingList() {
- Intent intent = new Intent(getBaseContext(), AwesomeBar.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_NO_HISTORY);
- intent.putExtra(AwesomeBar.TARGET_KEY, AwesomeBar.Target.CURRENT_TAB.toString());
- intent.putExtra(AwesomeBar.READING_LIST_KEY, true);
-
- int requestCode = GeckoAppShell.sActivityHelper.makeRequestCodeForAwesomebar();
- startActivityForResult(intent, requestCode);
- }
-
- @Override
- public void onBackPressed() {
- if (autoHideTabs()) {
- return;
- }
-
- if (mDoorHangerPopup != null && mDoorHangerPopup.isShowing()) {
- mDoorHangerPopup.dismiss();
- return;
- }
-
- if (mFullScreenPluginView != null) {
- GeckoAppShell.onFullScreenPluginHidden(mFullScreenPluginView);
- removeFullScreenPluginView(mFullScreenPluginView);
- return;
- }
-
- if (mLayerView != null && mLayerView.isFullScreen()) {
- GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("FullScreen:Exit", null));
- return;
- }
-
- Tabs tabs = Tabs.getInstance();
- Tab tab = tabs.getSelectedTab();
- if (tab == null) {
- moveTaskToBack(true);
- return;
- }
-
- if (tab.doBack())
- return;
-
- if (tab.isExternal()) {
- moveTaskToBack(true);
- tabs.closeTab(tab);
- return;
- }
-
- int parentId = tab.getParentId();
- Tab parent = tabs.getTab(parentId);
- if (parent != null) {
- // The back button should always return to the parent (not a sibling).
- tabs.closeTab(tab, parent);
- return;
- }
-
- moveTaskToBack(true);
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (!GeckoAppShell.sActivityHelper.handleActivityResult(requestCode, resultCode, data)) {
- super.onActivityResult(requestCode, resultCode, data);
- }
- }
-
- public AbsoluteLayout getPluginContainer() { return mPluginContainer; }
-
- // Accelerometer.
- @Override
- public void onAccuracyChanged(Sensor sensor, int accuracy) {
- }
-
- @Override
- public void onSensorChanged(SensorEvent event) {
- GeckoAppShell.sendEventToGecko(GeckoEvent.createSensorEvent(event));
- }
-
- // Geolocation.
- @Override
- public void onLocationChanged(Location location) {
- // No logging here: user-identifying information.
- GeckoAppShell.sendEventToGecko(GeckoEvent.createLocationEvent(location));
- }
-
- @Override
- public void onProviderDisabled(String provider)
- {
- }
-
- @Override
- public void onProviderEnabled(String provider)
- {
- }
-
- @Override
- public void onStatusChanged(String provider, int status, Bundle extras)
- {
- }
-
- // Called when a Gecko Hal WakeLock is changed
- public void notifyWakeLockChanged(String topic, String state) {
- PowerManager.WakeLock wl = mWakeLocks.get(topic);
- if (state.equals("locked-foreground") && wl == null) {
- PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
-
- if (CPU.equals(topic)) {
- wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, topic);
- } else if (SCREEN.equals(topic)) {
- wl = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, topic);
- }
-
- if (wl != null) {
- wl.acquire();
- mWakeLocks.put(topic, wl);
- }
- } else if (!state.equals("locked-foreground") && wl != null) {
- wl.release();
- mWakeLocks.remove(topic);
- }
- }
-
- public void notifyCheckUpdateResult(String result) {
- GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Update:CheckResult", result));
- }
-
- protected void geckoConnected() {
- mLayerView.geckoConnected();
- }
-
- public void setAccessibilityEnabled(boolean enabled) {
- }
-
- public static class MainLayout extends RelativeLayout {
- private TouchEventInterceptor mTouchEventInterceptor;
- private MotionEventInterceptor mMotionEventInterceptor;
-
- public MainLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public void setTouchEventInterceptor(TouchEventInterceptor interceptor) {
- mTouchEventInterceptor = interceptor;
- }
-
- public void setMotionEventInterceptor(MotionEventInterceptor interceptor) {
- mMotionEventInterceptor = interceptor;
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent event) {
- if (mTouchEventInterceptor != null && mTouchEventInterceptor.onInterceptTouchEvent(this, event)) {
- return true;
- }
- return super.onInterceptTouchEvent(event);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (mTouchEventInterceptor != null && mTouchEventInterceptor.onTouch(this, event)) {
- return true;
- }
- return super.onTouchEvent(event);
- }
-
- @Override
- public boolean onGenericMotionEvent(MotionEvent event) {
- if (mMotionEventInterceptor != null && mMotionEventInterceptor.onInterceptMotionEvent(this, event)) {
- return true;
- }
- return super.onGenericMotionEvent(event);
- }
-
- @Override
- public void setDrawingCacheEnabled(boolean enabled) {
- // Instead of setting drawing cache in the view itself, we simply
- // enable drawing caching on its children. This is mainly used in
- // animations (see PropertyAnimator)
- super.setChildrenDrawnWithCacheEnabled(enabled);
- }
- }
-
- private class FullScreenHolder extends FrameLayout {
-
- public FullScreenHolder(Context ctx) {
- super(ctx);
- }
-
- @Override
- public void addView(View view, int index) {
- /**
- * This normally gets called when Flash adds a separate SurfaceView
- * for the video. It is unhappy if we have the LayerView underneath
- * it for some reason so we need to hide that. Hiding the LayerView causes
- * its surface to be destroyed, which causes a pause composition
- * event to be sent to Gecko. We synchronously wait for that to be
- * processed. Simultaneously, however, Flash is waiting on a mutex so
- * the post() below is an attempt to avoid a deadlock.
- */
- super.addView(view, index);
-
- ThreadUtils.postToUiThread(new Runnable() {
- @Override
- public void run() {
- mLayerView.hide();
- }
- });
- }
-
- /**
- * The methods below are simply copied from what Android WebKit does.
- * It wasn't ever called in my testing, but might as well
- * keep it in case it is for some reason. The methods
- * all return true because we don't want any events
- * leaking out from the fullscreen view.
- */
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (event.isSystem()) {
- return super.onKeyDown(keyCode, event);
- }
- mFullScreenPluginView.onKeyDown(keyCode, event);
- return true;
- }
-
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- if (event.isSystem()) {
- return super.onKeyUp(keyCode, event);
- }
- mFullScreenPluginView.onKeyUp(keyCode, event);
- return true;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- return true;
- }
-
- @Override
- public boolean onTrackballEvent(MotionEvent event) {
- mFullScreenPluginView.onTrackballEvent(event);
- return true;
- }
- }
-
- protected NotificationClient makeNotificationClient() {
- // Don't use a notification service; we may be killed in the background
- // during downloads.
- return new AppNotificationClient(getApplicationContext());
- }
-
- private int getVersionCode() {
- int versionCode = 0;
- try {
- versionCode = getPackageManager().getPackageInfo(getPackageName(), 0).versionCode;
- } catch (NameNotFoundException e) {
- Log.wtf(LOGTAG, getPackageName() + " not found", e);
- }
- return versionCode;
- }
-}
diff --git a/mobile/android/base/GeckoAppShell.java b/mobile/android/base/GeckoAppShell.java
deleted file mode 100644
index 9107eab7a..000000000
--- a/mobile/android/base/GeckoAppShell.java
+++ /dev/null
@@ -1,2500 +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.gecko;
-
-import org.mozilla.gecko.gfx.BitmapUtils;
-import org.mozilla.gecko.gfx.GeckoLayerClient;
-import org.mozilla.gecko.gfx.GfxInfoThread;
-import org.mozilla.gecko.gfx.LayerView;
-import org.mozilla.gecko.gfx.PanZoomController;
-import org.mozilla.gecko.mozglue.GeckoLoader;
-import org.mozilla.gecko.util.EventDispatcher;
-import org.mozilla.gecko.util.GeckoEventListener;
-import org.mozilla.gecko.util.HardwareUtils;
-import org.mozilla.gecko.util.ThreadUtils;
-
-import android.app.Activity;
-import android.app.ActivityManager;
-import android.app.PendingIntent;
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.content.pm.Signature;
-import android.content.res.TypedArray;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.ImageFormat;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.SurfaceTexture;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.hardware.Sensor;
-import android.hardware.SensorManager;
-import android.hardware.SensorEventListener;
-import android.location.Criteria;
-import android.location.Location;
-import android.location.LocationListener;
-import android.location.LocationManager;
-import android.media.MediaScannerConnection;
-import android.media.MediaScannerConnection.MediaScannerConnectionClient;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Looper;
-import android.os.Message;
-import android.os.MessageQueue;
-import android.os.SystemClock;
-import android.os.Vibrator;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.Base64;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.view.ContextThemeWrapper;
-import android.view.HapticFeedbackConstants;
-import android.view.Surface;
-import android.view.SurfaceView;
-import android.view.TextureView;
-import android.view.View;
-import android.view.inputmethod.InputMethodManager;
-import android.webkit.MimeTypeMap;
-import android.widget.AbsoluteLayout;
-import android.widget.Toast;
-
-import java.io.BufferedReader;
-import java.io.Closeable;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.net.Proxy;
-import java.net.ProxySelector;
-import java.net.URI;
-import java.net.URL;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.StringTokenizer;
-import java.util.TreeMap;
-
-public class GeckoAppShell
-{
- private static final String LOGTAG = "GeckoAppShell";
-
- // static members only
- private GeckoAppShell() { }
-
- static private LinkedList<GeckoEvent> gPendingEvents =
- new LinkedList<GeckoEvent>();
-
- static private boolean gRestartScheduled = false;
-
- static private GeckoEditableListener mEditableListener = null;
-
- static private final HashMap<String, String>
- mAlertCookies = new HashMap<String, String>();
-
- /* Keep in sync with constants found here:
- http://mxr.mozilla.org/mozilla-central/source/uriloader/base/nsIWebProgressListener.idl
- */
- static public final int WPL_STATE_START = 0x00000001;
- static public final int WPL_STATE_STOP = 0x00000010;
- static public final int WPL_STATE_IS_DOCUMENT = 0x00020000;
- static public final int WPL_STATE_IS_NETWORK = 0x00040000;
-
- public static final String SHORTCUT_TYPE_WEBAPP = "webapp";
- public static final String SHORTCUT_TYPE_BOOKMARK = "bookmark";
-
- static private final boolean LOGGING = false;
-
- static private int sDensityDpi = 0;
-
- private static final EventDispatcher sEventDispatcher = new EventDispatcher();
-
- /* Default colors. */
- private static final float[] DEFAULT_LAUNCHER_ICON_HSV = { 32.0f, 1.0f, 1.0f };
-
- /* Is the value in sVibrationEndTime valid? */
- private static boolean sVibrationMaybePlaying = false;
-
- /* Time (in System.nanoTime() units) when the currently-playing vibration
- * is scheduled to end. This value is valid only when
- * sVibrationMaybePlaying is true. */
- private static long sVibrationEndTime = 0;
-
- /* Default value of how fast we should hint the Android sensors. */
- private static int sDefaultSensorHint = 100;
-
- private static Sensor gAccelerometerSensor = null;
- private static Sensor gLinearAccelerometerSensor = null;
- private static Sensor gGyroscopeSensor = null;
- private static Sensor gOrientationSensor = null;
- private static Sensor gProximitySensor = null;
- private static Sensor gLightSensor = null;
-
- private static volatile boolean mLocationHighAccuracy;
-
- public static ActivityHandlerHelper sActivityHelper = new ActivityHandlerHelper();
- static NotificationClient sNotificationClient;
-
- /* The Android-side API: API methods that Android calls */
-
- // Initialization methods
- public static native void nativeInit();
-
- // helper methods
- // public static native void setSurfaceView(GeckoSurfaceView sv);
- public static native void setLayerClient(GeckoLayerClient client);
- public static native void onResume();
- public static void callObserver(String observerKey, String topic, String data) {
- sendEventToGecko(GeckoEvent.createCallObserverEvent(observerKey, topic, data));
- }
- public static void removeObserver(String observerKey) {
- sendEventToGecko(GeckoEvent.createRemoveObserverEvent(observerKey));
- }
- public static native Message getNextMessageFromQueue(MessageQueue queue);
- public static native void onSurfaceTextureFrameAvailable(Object surfaceTexture, int id);
-
- public static void registerGlobalExceptionHandler() {
- Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
- @Override
- public void uncaughtException(Thread thread, Throwable e) {
- // If the uncaught exception was rethrown, walk the exception `cause` chain to find
- // the original exception so Socorro can correctly collate related crash reports.
- Throwable cause;
- while ((cause = e.getCause()) != null) {
- e = cause;
- }
-
- try {
- Log.e(LOGTAG, ">>> REPORTING UNCAUGHT EXCEPTION FROM THREAD "
- + thread.getId() + " (\"" + thread.getName() + "\")", e);
-
- if (e instanceof OutOfMemoryError) {
- SharedPreferences prefs =
- getContext().getSharedPreferences(GeckoApp.PREFS_NAME, 0);
- SharedPreferences.Editor editor = prefs.edit();
- editor.putBoolean(GeckoApp.PREFS_OOM_EXCEPTION, true);
- editor.commit();
- }
- } finally {
- reportJavaCrash(getStackTraceString(e));
- }
- }
- });
- }
-
- private static String getStackTraceString(Throwable e) {
- StringWriter sw = new StringWriter();
- PrintWriter pw = new PrintWriter(sw);
- e.printStackTrace(pw);
- pw.flush();
- return sw.toString();
- }
-
- private static native void reportJavaCrash(String stackTrace);
-
- public static void notifyUriVisited(String uri) {
- sendEventToGecko(GeckoEvent.createVisitedEvent(uri));
- }
-
- public static native void processNextNativeEvent(boolean mayWait);
-
- public static native void notifyBatteryChange(double aLevel, boolean aCharging, double aRemainingTime);
-
- public static native void scheduleComposite();
-
- // Resuming the compositor is a synchronous request, so be
- // careful of possible deadlock. Resuming the compositor will also cause
- // a composition, so there is no need to schedule a composition after
- // resuming.
- public static native void scheduleResumeComposition(int width, int height);
-
- public static native float computeRenderIntegrity();
-
- public static native SurfaceBits getSurfaceBits(Surface surface);
-
- public static native void onFullScreenPluginHidden(View view);
-
- private static final class GeckoMediaScannerClient implements MediaScannerConnectionClient {
- private final String mFile;
- private final String mMimeType;
- private MediaScannerConnection mScanner;
-
- public static void startScan(Context context, String file, String mimeType) {
- new GeckoMediaScannerClient(context, file, mimeType);
- }
-
- private GeckoMediaScannerClient(Context context, String file, String mimeType) {
- mFile = file;
- mMimeType = mimeType;
- mScanner = new MediaScannerConnection(context, this);
- mScanner.connect();
- }
-
- @Override
- public void onMediaScannerConnected() {
- mScanner.scanFile(mFile, mMimeType);
- }
-
- @Override
- public void onScanCompleted(String path, Uri uri) {
- if(path.equals(mFile)) {
- mScanner.disconnect();
- mScanner = null;
- }
- }
- }
-
- private static LayerView sLayerView;
-
- public static void setLayerView(LayerView lv) {
- sLayerView = lv;
- }
-
- public static LayerView getLayerView() {
- return sLayerView;
- }
-
- public static void runGecko(String apkPath, String args, String url, String type) {
- Looper.prepare();
-
- // run gecko -- it will spawn its own thread
- GeckoAppShell.nativeInit();
-
- if (sLayerView != null)
- GeckoAppShell.setLayerClient(sLayerView.getLayerClient());
-
- // First argument is the .apk path
- String combinedArgs = apkPath + " -greomni " + apkPath;
- if (args != null)
- combinedArgs += " " + args;
- if (url != null)
- combinedArgs += " -url " + url;
- if (type != null)
- combinedArgs += " " + type;
-
- DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
- combinedArgs += " -width " + metrics.widthPixels + " -height " + metrics.heightPixels;
-
- ThreadUtils.postToUiThread(new Runnable() {
- @Override
- public void run() {
- geckoLoaded();
- }
- });
-
- // and go
- GeckoLoader.nativeRun(combinedArgs);
- }
-
- // Called on the UI thread after Gecko loads.
- private static void geckoLoaded() {
- GeckoEditable editable = new GeckoEditable();
- // install the gecko => editable listener
- mEditableListener = editable;
- }
-
- static void sendPendingEventsToGecko() {
- try {
- while (!gPendingEvents.isEmpty()) {
- GeckoEvent e = gPendingEvents.removeFirst();
- notifyGeckoOfEvent(e);
- }
- } catch (NoSuchElementException e) {}
- }
-
- /* This method is referenced by Robocop via reflection. */
- public static void sendEventToGecko(GeckoEvent e) {
- if (GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoRunning)) {
- notifyGeckoOfEvent(e);
- } else {
- gPendingEvents.addLast(e);
- }
- }
-
- // Tell the Gecko event loop that an event is available.
- public static native void notifyGeckoOfEvent(GeckoEvent event);
-
- /*
- * The Gecko-side API: API methods that Gecko calls
- */
- public static void notifyIME(int type) {
- if (mEditableListener != null) {
- mEditableListener.notifyIME(type);
- }
- }
-
- public static void notifyIMEContext(int state, String typeHint,
- String modeHint, String actionHint) {
- if (mEditableListener != null) {
- mEditableListener.notifyIMEContext(state, typeHint,
- modeHint, actionHint);
- }
- }
-
- public static void notifyIMEChange(String text, int start, int end, int newEnd) {
- if (newEnd < 0) { // Selection change
- mEditableListener.onSelectionChange(start, end);
- } else { // Text change
- mEditableListener.onTextChange(text, start, end, newEnd);
- }
- }
-
- private static final Object sEventAckLock = new Object();
- private static boolean sWaitingForEventAck;
-
- // Block the current thread until the Gecko event loop is caught up
- public static void sendEventToGeckoSync(GeckoEvent e) {
- e.setAckNeeded(true);
-
- long time = SystemClock.uptimeMillis();
- boolean isUiThread = ThreadUtils.isOnUiThread();
-
- synchronized (sEventAckLock) {
- if (sWaitingForEventAck) {
- // should never happen since we always leave it as false when we exit this function.
- Log.e(LOGTAG, "geckoEventSync() may have been called twice concurrently!", new Exception());
- // fall through for graceful handling
- }
-
- sendEventToGecko(e);
- sWaitingForEventAck = true;
- while (true) {
- try {
- sEventAckLock.wait(1000);
- } catch (InterruptedException ie) {
- }
- if (!sWaitingForEventAck) {
- // response received
- break;
- }
- long waited = SystemClock.uptimeMillis() - time;
- Log.d(LOGTAG, "Gecko event sync taking too long: " + waited + "ms");
- }
- }
- }
-
- // Signal the Java thread that it's time to wake up
- public static void acknowledgeEvent() {
- synchronized (sEventAckLock) {
- sWaitingForEventAck = false;
- sEventAckLock.notifyAll();
- }
- }
-
- private static float getLocationAccuracy(Location location) {
- float radius = location.getAccuracy();
- return (location.hasAccuracy() && radius > 0) ? radius : 1001;
- }
-
- private static Location getLastKnownLocation(LocationManager lm) {
- Location lastKnownLocation = null;
- List<String> providers = lm.getAllProviders();
-
- for (String provider : providers) {
- Location location = lm.getLastKnownLocation(provider);
- if (location == null) {
- continue;
- }
-
- if (lastKnownLocation == null) {
- lastKnownLocation = location;
- continue;
- }
-
- long timeDiff = location.getTime() - lastKnownLocation.getTime();
- if (timeDiff > 0 ||
- (timeDiff == 0 &&
- getLocationAccuracy(location) < getLocationAccuracy(lastKnownLocation))) {
- lastKnownLocation = location;
- }
- }
-
- return lastKnownLocation;
- }
-
- public static void enableLocation(final boolean enable) {
- ThreadUtils.postToUiThread(new Runnable() {
- @Override
- public void run() {
- LocationManager lm = getLocationManager(getContext());
- if (lm == null) {
- return;
- }
-
- if (enable) {
- Location lastKnownLocation = getLastKnownLocation(lm);
- if (lastKnownLocation != null) {
- getGeckoInterface().getLocationListener().onLocationChanged(lastKnownLocation);
- }
-
- Criteria criteria = new Criteria();
- criteria.setSpeedRequired(false);
- criteria.setBearingRequired(false);
- criteria.setAltitudeRequired(false);
- if (mLocationHighAccuracy) {
- criteria.setAccuracy(Criteria.ACCURACY_FINE);
- criteria.setCostAllowed(true);
- criteria.setPowerRequirement(Criteria.POWER_HIGH);
- } else {
- criteria.setAccuracy(Criteria.ACCURACY_COARSE);
- criteria.setCostAllowed(false);
- criteria.setPowerRequirement(Criteria.POWER_LOW);
- }
-
- String provider = lm.getBestProvider(criteria, true);
- if (provider == null)
- return;
-
- Looper l = Looper.getMainLooper();
- lm.requestLocationUpdates(provider, 100, (float).5, getGeckoInterface().getLocationListener(), l);
- } else {
- lm.removeUpdates(getGeckoInterface().getLocationListener());
- }
- }
- });
- }
-
- private static LocationManager getLocationManager(Context context) {
- try {
- return (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
- } catch (NoSuchFieldError e) {
- // Some Tegras throw exceptions about missing the CONTROL_LOCATION_UPDATES permission,
- // which allows enabling/disabling location update notifications from the cell radio.
- // CONTROL_LOCATION_UPDATES is not for use by normal applications, but we might be
- // hitting this problem if the Tegras are confused about missing cell radios.
- Log.e(LOGTAG, "LOCATION_SERVICE not found?!", e);
- return null;
- }
- }
-
- public static void enableLocationHighAccuracy(final boolean enable) {
- mLocationHighAccuracy = enable;
- }
-
- public static void enableSensor(int aSensortype) {
- GeckoInterface gi = getGeckoInterface();
- if (gi == null)
- return;
- SensorManager sm = (SensorManager)
- getContext().getSystemService(Context.SENSOR_SERVICE);
-
- switch(aSensortype) {
- case GeckoHalDefines.SENSOR_ORIENTATION:
- if(gOrientationSensor == null)
- gOrientationSensor = sm.getDefaultSensor(Sensor.TYPE_ORIENTATION);
- if (gOrientationSensor != null)
- sm.registerListener(gi.getSensorEventListener(), gOrientationSensor, sDefaultSensorHint);
- break;
-
- case GeckoHalDefines.SENSOR_ACCELERATION:
- if(gAccelerometerSensor == null)
- gAccelerometerSensor = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
- if (gAccelerometerSensor != null)
- sm.registerListener(gi.getSensorEventListener(), gAccelerometerSensor, sDefaultSensorHint);
- break;
-
- case GeckoHalDefines.SENSOR_PROXIMITY:
- if(gProximitySensor == null )
- gProximitySensor = sm.getDefaultSensor(Sensor.TYPE_PROXIMITY);
- if (gProximitySensor != null)
- sm.registerListener(gi.getSensorEventListener(), gProximitySensor, SensorManager.SENSOR_DELAY_NORMAL);
- break;
-
- case GeckoHalDefines.SENSOR_LIGHT:
- if(gLightSensor == null)
- gLightSensor = sm.getDefaultSensor(Sensor.TYPE_LIGHT);
- if (gLightSensor != null)
- sm.registerListener(gi.getSensorEventListener(), gLightSensor, SensorManager.SENSOR_DELAY_NORMAL);
- break;
-
- case GeckoHalDefines.SENSOR_LINEAR_ACCELERATION:
- if(gLinearAccelerometerSensor == null)
- gLinearAccelerometerSensor = sm.getDefaultSensor(10 /* API Level 9 - TYPE_LINEAR_ACCELERATION */);
- if (gLinearAccelerometerSensor != null)
- sm.registerListener(gi.getSensorEventListener(), gLinearAccelerometerSensor, sDefaultSensorHint);
- break;
-
- case GeckoHalDefines.SENSOR_GYROSCOPE:
- if(gGyroscopeSensor == null)
- gGyroscopeSensor = sm.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
- if (gGyroscopeSensor != null)
- sm.registerListener(gi.getSensorEventListener(), gGyroscopeSensor, sDefaultSensorHint);
- break;
- default:
- Log.w(LOGTAG, "Error! Can't enable unknown SENSOR type " + aSensortype);
- }
- }
-
- public static void disableSensor(int aSensortype) {
- GeckoInterface gi = getGeckoInterface();
- if (gi == null)
- return;
-
- SensorManager sm = (SensorManager)
- getContext().getSystemService(Context.SENSOR_SERVICE);
-
- switch (aSensortype) {
- case GeckoHalDefines.SENSOR_ORIENTATION:
- if (gOrientationSensor != null)
- sm.unregisterListener(gi.getSensorEventListener(), gOrientationSensor);
- break;
-
- case GeckoHalDefines.SENSOR_ACCELERATION:
- if (gAccelerometerSensor != null)
- sm.unregisterListener(gi.getSensorEventListener(), gAccelerometerSensor);
- break;
-
- case GeckoHalDefines.SENSOR_PROXIMITY:
- if (gProximitySensor != null)
- sm.unregisterListener(gi.getSensorEventListener(), gProximitySensor);
- break;
-
- case GeckoHalDefines.SENSOR_LIGHT:
- if (gLightSensor != null)
- sm.unregisterListener(gi.getSensorEventListener(), gLightSensor);
- break;
-
- case GeckoHalDefines.SENSOR_LINEAR_ACCELERATION:
- if (gLinearAccelerometerSensor != null)
- sm.unregisterListener(gi.getSensorEventListener(), gLinearAccelerometerSensor);
- break;
-
- case GeckoHalDefines.SENSOR_GYROSCOPE:
- if (gGyroscopeSensor != null)
- sm.unregisterListener(gi.getSensorEventListener(), gGyroscopeSensor);
- break;
- default:
- Log.w(LOGTAG, "Error! Can't disable unknown SENSOR type " + aSensortype);
- }
- }
-
- public static void moveTaskToBack() {
- if (getGeckoInterface() != null)
- getGeckoInterface().getActivity().moveTaskToBack(true);
- }
-
- public static void returnIMEQueryResult(String result, int selectionStart, int selectionLength) {
- // This method may be called from JNI to report Gecko's current selection indexes, but
- // Native Fennec doesn't care because the Java code already knows the selection indexes.
- }
-
- static void onXreExit() {
- // The launch state can only be Launched or GeckoRunning at this point
- GeckoThread.setLaunchState(GeckoThread.LaunchState.GeckoExiting);
- if (getGeckoInterface() != null) {
- if (gRestartScheduled) {
- getGeckoInterface().doRestart();
- } else {
- getGeckoInterface().getActivity().finish();
- }
- }
-
- Log.d(LOGTAG, "Killing via System.exit()");
- System.exit(0);
- }
-
- static void scheduleRestart() {
- gRestartScheduled = true;
- }
-
- public static File preInstallWebApp(String aTitle, String aURI, String aUniqueURI) {
- int index = WebAppAllocator.getInstance(getContext()).findAndAllocateIndex(aUniqueURI, aTitle, (String) null);
- GeckoProfile profile = GeckoProfile.get(getContext(), "webapp" + index);
- return profile.getDir();
- }
-
- public static void postInstallWebApp(String aTitle, String aURI, String aUniqueURI, String aIconURL) {
- WebAppAllocator allocator = WebAppAllocator.getInstance(getContext());
- int index = allocator.getIndexForApp(aUniqueURI);
- assert index != -1 && aIconURL != null;
- allocator.updateAppAllocation(aUniqueURI, index, BitmapUtils.getBitmapFromDataURI(aIconURL));
- createShortcut(aTitle, aURI, aUniqueURI, aIconURL, "webapp");
- }
-
- public static Intent getWebAppIntent(String aURI, String aUniqueURI, String aTitle, Bitmap aIcon) {
- int index;
- if (aIcon != null && !TextUtils.isEmpty(aTitle))
- index = WebAppAllocator.getInstance(getContext()).findAndAllocateIndex(aUniqueURI, aTitle, aIcon);
- else
- index = WebAppAllocator.getInstance(getContext()).getIndexForApp(aUniqueURI);
-
- if (index == -1)
- return null;
-
- return getWebAppIntent(index, aURI);
- }
-
- public static Intent getWebAppIntent(int aIndex, String aURI) {
- Intent intent = new Intent();
- intent.setAction(GeckoApp.ACTION_WEBAPP_PREFIX + aIndex);
- intent.setData(Uri.parse(aURI));
- intent.setClassName(AppConstants.ANDROID_PACKAGE_NAME,
- AppConstants.ANDROID_PACKAGE_NAME + ".WebApps$WebApp" + aIndex);
- return intent;
- }
-
- // "Installs" an application by creating a shortcut
- // This is the entry point from AndroidBridge.h
- static void createShortcut(String aTitle, String aURI, String aIconData, String aType) {
- if ("webapp".equals(aType)) {
- Log.w(LOGTAG, "createShortcut with no unique URI should not be used for aType = webapp!");
- }
-
- createShortcut(aTitle, aURI, aURI, aIconData, aType);
- }
-
- // internal, for non-webapps
- static void createShortcut(String aTitle, String aURI, Bitmap aBitmap, String aType) {
- createShortcut(aTitle, aURI, aURI, aBitmap, aType);
- }
-
- // internal, for webapps
- static void createShortcut(String aTitle, String aURI, String aUniqueURI, String aIconData, String aType) {
- createShortcut(aTitle, aURI, aUniqueURI, BitmapUtils.getBitmapFromDataURI(aIconData), aType);
- }
-
- public static void createShortcut(final String aTitle, final String aURI, final String aUniqueURI,
- final Bitmap aIcon, final String aType)
- {
- ThreadUtils.postToBackgroundThread(new Runnable() {
- @Override
- public void run() {
- // the intent to be launched by the shortcut
- Intent shortcutIntent;
- if (aType.equalsIgnoreCase(SHORTCUT_TYPE_WEBAPP)) {
- shortcutIntent = getWebAppIntent(aURI, aUniqueURI, aTitle, aIcon);
- } else {
- shortcutIntent = new Intent();
- shortcutIntent.setAction(GeckoApp.ACTION_BOOKMARK);
- shortcutIntent.setData(Uri.parse(aURI));
- shortcutIntent.setClassName(AppConstants.ANDROID_PACKAGE_NAME,
- AppConstants.BROWSER_INTENT_CLASS);
- }
-
- Intent intent = new Intent();
- intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
- if (aTitle != null)
- intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, aTitle);
- else
- intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, aURI);
- intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, getLauncherIcon(aIcon, aType));
-
- // Do not allow duplicate items
- intent.putExtra("duplicate", false);
-
- intent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
- getContext().sendBroadcast(intent);
- }
- });
- }
-
- public static void removeShortcut(final String aTitle, final String aURI, final String aType) {
- removeShortcut(aTitle, aURI, null, aType);
- }
-
- public static void removeShortcut(final String aTitle, final String aURI, final String aUniqueURI, final String aType) {
- ThreadUtils.postToBackgroundThread(new Runnable() {
- @Override
- public void run() {
- // the intent to be launched by the shortcut
- Intent shortcutIntent;
- if (aType.equalsIgnoreCase(SHORTCUT_TYPE_WEBAPP)) {
- int index = WebAppAllocator.getInstance(getContext()).getIndexForApp(aUniqueURI);
- shortcutIntent = getWebAppIntent(aURI, aUniqueURI, "", null);
- if (shortcutIntent == null)
- return;
- } else {
- shortcutIntent = new Intent();
- shortcutIntent.setAction(GeckoApp.ACTION_BOOKMARK);
- shortcutIntent.setClassName(AppConstants.ANDROID_PACKAGE_NAME,
- AppConstants.BROWSER_INTENT_CLASS);
- shortcutIntent.setData(Uri.parse(aURI));
- }
-
- Intent intent = new Intent();
- intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
- if (aTitle != null)
- intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, aTitle);
- else
- intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, aURI);
-
- intent.setAction("com.android.launcher.action.UNINSTALL_SHORTCUT");
- getContext().sendBroadcast(intent);
- }
- });
- }
-
- public static void uninstallWebApp(final String uniqueURI) {
- // On uninstall, we need to do a couple of things:
- // 1. nuke the running app process.
- // 2. nuke the profile that was assigned to that webapp
- ThreadUtils.postToBackgroundThread(new Runnable() {
- @Override
- public void run() {
- int index = WebAppAllocator.getInstance(getContext()).releaseIndexForApp(uniqueURI);
-
- // if -1, nothing to do; we didn't think it was installed anyway
- if (index == -1)
- return;
-
- // kill the app if it's running
- String targetProcessName = getContext().getPackageName();
- targetProcessName = targetProcessName + ":" + targetProcessName + ".WebApp" + index;
-
- ActivityManager am = (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE);
- List<ActivityManager.RunningAppProcessInfo> procs = am.getRunningAppProcesses();
- if (procs != null) {
- for (ActivityManager.RunningAppProcessInfo proc : procs) {
- if (proc.processName.equals(targetProcessName)) {
- android.os.Process.killProcess(proc.pid);
- break;
- }
- }
- }
-
- // then nuke the profile
- GeckoProfile.removeProfile(getContext(), "webapp" + index);
- }
- });
- }
-
- static public int getPreferredIconSize() {
- if (android.os.Build.VERSION.SDK_INT >= 11) {
- ActivityManager am = (ActivityManager)getContext().getSystemService(Context.ACTIVITY_SERVICE);
- return am.getLauncherLargeIconSize();
- } else {
- switch (getDpi()) {
- case DisplayMetrics.DENSITY_MEDIUM:
- return 48;
- case DisplayMetrics.DENSITY_XHIGH:
- return 96;
- case DisplayMetrics.DENSITY_HIGH:
- default:
- return 72;
- }
- }
- }
-
- static private Bitmap getLauncherIcon(Bitmap aSource, String aType) {
- final int kOffset = 6;
- final int kRadius = 5;
- int size = getPreferredIconSize();
- int insetSize = aSource != null ? size * 2 / 3 : size;
-
- Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(bitmap);
-
- if (aType.equalsIgnoreCase(SHORTCUT_TYPE_WEBAPP)) {
- Rect iconBounds = new Rect(0, 0, size, size);
- canvas.drawBitmap(aSource, null, iconBounds, null);
- return bitmap;
- }
-
- // draw a base color
- Paint paint = new Paint();
- if (aSource == null) {
- // If we aren't drawing a favicon, just use an orange color.
- paint.setColor(Color.HSVToColor(DEFAULT_LAUNCHER_ICON_HSV));
- canvas.drawRoundRect(new RectF(kOffset, kOffset, size - kOffset, size - kOffset), kRadius, kRadius, paint);
- } else {
- // otherwise use the dominant color from the icon + a layer of transparent white to lighten it somewhat
- int color = BitmapUtils.getDominantColor(aSource);
- paint.setColor(color);
- canvas.drawRoundRect(new RectF(kOffset, kOffset, size - kOffset, size - kOffset), kRadius, kRadius, paint);
- paint.setColor(Color.argb(100, 255, 255, 255));
- canvas.drawRoundRect(new RectF(kOffset, kOffset, size - kOffset, size - kOffset), kRadius, kRadius, paint);
- }
-
- // draw the overlay
- Bitmap overlay = BitmapUtils.decodeResource(getContext(), R.drawable.home_bg);
- canvas.drawBitmap(overlay, null, new Rect(0, 0, size, size), null);
-
- // draw the favicon
- if (aSource == null)
- aSource = BitmapUtils.decodeResource(getContext(), R.drawable.home_star);
-
- // by default, we scale the icon to this size
- int sWidth = insetSize / 2;
- int sHeight = sWidth;
-
- if (aSource.getWidth() > insetSize || aSource.getHeight() > insetSize) {
- // however, if the icon is larger than our minimum, we allow it to be drawn slightly larger
- // (but not necessarily at its full resolution)
- sWidth = Math.min(size / 3, aSource.getWidth() / 2);
- sHeight = Math.min(size / 3, aSource.getHeight() / 2);
- }
-
- int halfSize = size / 2;
- canvas.drawBitmap(aSource,
- null,
- new Rect(halfSize - sWidth,
- halfSize - sHeight,
- halfSize + sWidth,
- halfSize + sHeight),
- null);
-
- return bitmap;
- }
-
- static String[] getHandlersForMimeType(String aMimeType, String aAction) {
- Intent intent = getIntentForActionString(aAction);
- if (aMimeType != null && aMimeType.length() > 0)
- intent.setType(aMimeType);
- return getHandlersForIntent(intent);
- }
-
- static String[] getHandlersForURL(String aURL, String aAction) {
- // aURL may contain the whole URL or just the protocol
- Uri uri = aURL.indexOf(':') >= 0 ? Uri.parse(aURL) : new Uri.Builder().scheme(aURL).build();
-
- Intent intent = getOpenURIIntent(getContext(), uri.toString(), "",
- TextUtils.isEmpty(aAction) ? Intent.ACTION_VIEW : aAction, "");
-
- return getHandlersForIntent(intent);
- }
-
- static boolean hasHandlersForIntent(Intent intent) {
- PackageManager pm = getContext().getPackageManager();
- List<ResolveInfo> list = pm.queryIntentActivities(intent, 0);
- return !list.isEmpty();
- }
-
- static String[] getHandlersForIntent(Intent intent) {
- PackageManager pm = getContext().getPackageManager();
- List<ResolveInfo> list = pm.queryIntentActivities(intent, 0);
- int numAttr = 4;
- String[] ret = new String[list.size() * numAttr];
- for (int i = 0; i < list.size(); i++) {
- ResolveInfo resolveInfo = list.get(i);
- ret[i * numAttr] = resolveInfo.loadLabel(pm).toString();
- if (resolveInfo.isDefault)
- ret[i * numAttr + 1] = "default";
- else
- ret[i * numAttr + 1] = "";
- ret[i * numAttr + 2] = resolveInfo.activityInfo.applicationInfo.packageName;
- ret[i * numAttr + 3] = resolveInfo.activityInfo.name;
- }
- return ret;
- }
-
- static Intent getIntentForActionString(String aAction) {
- // Default to the view action if no other action as been specified.
- if (TextUtils.isEmpty(aAction)) {
- return new Intent(Intent.ACTION_VIEW);
- }
- return new Intent(aAction);
- }
-
- static String getExtensionFromMimeType(String aMimeType) {
- return MimeTypeMap.getSingleton().getExtensionFromMimeType(aMimeType);
- }
-
- static String getMimeTypeFromExtensions(String aFileExt) {
- MimeTypeMap mtm = MimeTypeMap.getSingleton();
- StringTokenizer st = new StringTokenizer(aFileExt, ".,; ");
- String type = null;
- String subType = null;
- while (st.hasMoreElements()) {
- String ext = st.nextToken();
- String mt = mtm.getMimeTypeFromExtension(ext);
- if (mt == null)
- continue;
- int slash = mt.indexOf('/');
- String tmpType = mt.substring(0, slash);
- if (!tmpType.equalsIgnoreCase(type))
- type = type == null ? tmpType : "*";
- String tmpSubType = mt.substring(slash + 1);
- if (!tmpSubType.equalsIgnoreCase(subType))
- subType = subType == null ? tmpSubType : "*";
- }
- if (type == null)
- type = "*";
- if (subType == null)
- subType = "*";
- return type + "/" + subType;
- }
-
- static void safeStreamClose(Closeable stream) {
- try {
- if (stream != null)
- stream.close();
- } catch (IOException e) {}
- }
-
- static void shareImage(String aSrc, String aType) {
-
- Intent intent = new Intent(Intent.ACTION_SEND);
- boolean isDataURI = aSrc.startsWith("data:");
- OutputStream os = null;
- File dir = GeckoApp.getTempDirectory();
-
- if (dir == null) {
- showImageShareFailureToast();
- return;
- }
-
- GeckoApp.deleteTempFiles();
-
- try {
- // Create a temporary file for the image
- File imageFile = File.createTempFile("image",
- "." + aType.replace("image/",""),
- dir);
- os = new FileOutputStream(imageFile);
-
- if (isDataURI) {
- // We are dealing with a Data URI
- int dataStart = aSrc.indexOf(',');
- byte[] buf = Base64.decode(aSrc.substring(dataStart+1), Base64.DEFAULT);
- os.write(buf);
- } else {
- // We are dealing with a URL
- InputStream is = null;
- try {
- URL url = new URL(aSrc);
- is = url.openStream();
- byte[] buf = new byte[2048];
- int length;
-
- while ((length = is.read(buf)) != -1) {
- os.write(buf, 0, length);
- }
- } finally {
- safeStreamClose(is);
- }
- }
- intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(imageFile));
-
- // If we were able to determine the image type, send that in the intent. Otherwise,
- // use a generic type.
- if (aType.startsWith("image/")) {
- intent.setType(aType);
- } else {
- intent.setType("image/*");
- }
- } catch (IOException e) {
- if (!isDataURI) {
- // If we failed, at least send through the URL link
- intent.putExtra(Intent.EXTRA_TEXT, aSrc);
- intent.setType("text/plain");
- } else {
- showImageShareFailureToast();
- return;
- }
- } finally {
- safeStreamClose(os);
- }
- getContext().startActivity(Intent.createChooser(intent,
- getContext().getResources().getString(R.string.share_title)));
- }
-
- // Don't fail silently, tell the user that we weren't able to share the image
- private static final void showImageShareFailureToast() {
- Toast toast = Toast.makeText(getContext(),
- getContext().getResources().getString(R.string.share_image_failed),
- Toast.LENGTH_SHORT);
- toast.show();
- }
-
- static boolean isUriSafeForScheme(Uri aUri) {
- // Bug 794034 - We don't want to pass MWI or USSD codes to the
- // dialer, and ensure the Uri class doesn't parse a URI
- // containing a fragment ('#')
- final String scheme = aUri.getScheme();
- if ("tel".equals(scheme) || "sms".equals(scheme)) {
- final String number = aUri.getSchemeSpecificPart();
- if (number.contains("#") || number.contains("*") || aUri.getFragment() != null) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Given the inputs to <code>getOpenURIIntent</code>, plus an optional
- * package name and class name, create and fire an intent to open the
- * provided URI.
- *
- * @param targetURI the string spec of the URI to open.
- * @param mimeType an optional MIME type string.
- * @param action an Android action specifier, such as
- * <code>Intent.ACTION_SEND</code>.
- * @param title the title to use in <code>ACTION_SEND</code> intents.
- * @return true if the activity started successfully; false otherwise.
- */
- static boolean openUriExternal(String targetURI,
- String mimeType,
- String packageName,
- String className,
- String action,
- String title) {
- final Context context = getContext();
- final Intent intent = getOpenURIIntent(context, targetURI,
- mimeType, action, title);
-
- if (intent == null) {
- return false;
- }
-
- if (packageName.length() > 0 && className.length() > 0) {
- intent.setClassName(packageName, className);
- }
-
- intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- try {
- context.startActivity(intent);
- return true;
- } catch (ActivityNotFoundException e) {
- return false;
- }
- }
-
- /**
- * Return a <code>Uri</code> instance which is equivalent to <code>u</code>,
- * but with a guaranteed-lowercase scheme as if the API level 16 method
- * <code>u.normalizeScheme</code> had been called.
- *
- * @param u the <code>Uri</code> to normalize.
- * @return a <code>Uri</code>, which might be <code>u</code>.
- */
- static Uri normalizeUriScheme(final Uri u) {
- final String scheme = u.getScheme();
- final String lower = scheme.toLowerCase(Locale.US);
- if (lower.equals(scheme)) {
- return u;
- }
-
- // Otherwise, return a new URI with a normalized scheme.
- return u.buildUpon().scheme(lower).build();
- }
-
- /**
- * Given a URI, a MIME type, and a title,
- * produce a share intent which can be used to query all activities
- * than can open the specified URI.
- *
- * @param context a <code>Context</code> instance.
- * @param targetURI the string spec of the URI to open.
- * @param mimeType an optional MIME type string.
- * @param title the title to use in <code>ACTION_SEND</code> intents.
- * @return an <code>Intent</code>, or <code>null</code> if none could be
- * produced.
- */
- static Intent getShareIntent(final Context context,
- final String targetURI,
- final String mimeType,
- final String title) {
- Intent shareIntent = getIntentForActionString(Intent.ACTION_SEND);
- shareIntent.putExtra(Intent.EXTRA_TEXT, targetURI);
- shareIntent.putExtra(Intent.EXTRA_SUBJECT, title);
-
- // Note that EXTRA_TITLE is intended to be used for share dialog
- // titles. Common usage (e.g., Pocket) suggests that it's sometimes
- // interpreted as an alternate to EXTRA_SUBJECT, so we include it.
- shareIntent.putExtra(Intent.EXTRA_TITLE, title);
-
- if (mimeType != null && mimeType.length() > 0) {
- shareIntent.setType(mimeType);
- }
-
- return shareIntent;
- }
-
- /**
- * Given a URI, a MIME type, an Android intent "action", and a title,
- * produce an intent which can be used to start an activity to open
- * the specified URI.
- *
- * @param context a <code>Context</code> instance.
- * @param targetURI the string spec of the URI to open.
- * @param mimeType an optional MIME type string.
- * @param action an Android action specifier, such as
- * <code>Intent.ACTION_SEND</code>.
- * @param title the title to use in <code>ACTION_SEND</code> intents.
- * @return an <code>Intent</code>, or <code>null</code> if none could be
- * produced.
- */
- static Intent getOpenURIIntent(final Context context,
- final String targetURI,
- final String mimeType,
- final String action,
- final String title) {
-
- if (action.equalsIgnoreCase(Intent.ACTION_SEND)) {
- Intent shareIntent = getShareIntent(context, targetURI, mimeType, title);
- return Intent.createChooser(shareIntent,
- context.getResources().getString(R.string.share_title));
- }
-
- final Uri uri = normalizeUriScheme(Uri.parse(targetURI));
- if (mimeType.length() > 0) {
- Intent intent = getIntentForActionString(action);
- intent.setDataAndType(uri, mimeType);
- return intent;
- }
-
- if (!isUriSafeForScheme(uri)) {
- return null;
- }
-
- final String scheme = uri.getScheme();
-
- final Intent intent;
-
- // Compute our most likely intent, then check to see if there are any
- // custom handlers that would apply.
- // Start with the original URI. If we end up modifying it, we'll
- // overwrite it.
- final Intent likelyIntent = getIntentForActionString(action);
- likelyIntent.setData(uri);
-
- if ("vnd.youtube".equals(scheme) && !hasHandlersForIntent(likelyIntent)) {
- // Special-case YouTube to use our own player if no system handler
- // exists.
- intent = new Intent(VideoPlayer.VIDEO_ACTION);
- intent.setClassName(AppConstants.ANDROID_PACKAGE_NAME,
- "org.mozilla.gecko.VideoPlayer");
- intent.setData(uri);
- } else {
- intent = likelyIntent;
- }
-
- // Have a special handling for SMS, as the message body
- // is not extracted from the URI automatically.
- if (!"sms".equals(scheme)) {
- return intent;
- }
-
- final String query = uri.getEncodedQuery();
- if (TextUtils.isEmpty(query)) {
- return intent;
- }
-
- final String[] fields = query.split("&");
- boolean foundBody = false;
- String resultQuery = "";
- for (String field : fields) {
- if (foundBody || !field.startsWith("body=")) {
- resultQuery = resultQuery.concat(resultQuery.length() > 0 ? "&" + field : field);
- continue;
- }
-
- // Found the first body param. Put it into the intent.
- final String body = Uri.decode(field.substring(5));
- intent.putExtra("sms_body", body);
- foundBody = true;
- }
-
- if (!foundBody) {
- // No need to rewrite the URI, then.
- return intent;
- }
-
- // Form a new URI without the body field in the query part, and
- // push that into the new Intent.
- final String newQuery = resultQuery.length() > 0 ? "?" + resultQuery : "";
- final Uri pruned = uri.buildUpon().encodedQuery(newQuery).build();
- intent.setData(pruned);
-
- return intent;
- }
-
- public static void setNotificationClient(NotificationClient client) {
- if (sNotificationClient == null) {
- sNotificationClient = client;
- } else {
- Log.d(LOGTAG, "Notification client already set");
- }
- }
-
- public static void showAlertNotification(String aImageUrl, String aAlertTitle, String aAlertText,
- String aAlertCookie, String aAlertName) {
- // The intent to launch when the user clicks the expanded notification
- String app = getContext().getClass().getName();
- Intent notificationIntent = new Intent(GeckoApp.ACTION_ALERT_CALLBACK);
- notificationIntent.setClassName(AppConstants.ANDROID_PACKAGE_NAME, app);
- notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
- int notificationID = aAlertName.hashCode();
-
- // Put the strings into the intent as an URI "alert:?name=<alertName>&app=<appName>&cookie=<cookie>"
- Uri.Builder b = new Uri.Builder();
- Uri dataUri = b.scheme("alert").path(Integer.toString(notificationID))
- .appendQueryParameter("name", aAlertName)
- .appendQueryParameter("cookie", aAlertCookie)
- .build();
- notificationIntent.setData(dataUri);
- PendingIntent contentIntent = PendingIntent.getActivity(
- getContext(), 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
-
- mAlertCookies.put(aAlertName, aAlertCookie);
- callObserver(aAlertName, "alertshow", aAlertCookie);
-
- sNotificationClient.add(notificationID, aImageUrl, aAlertTitle, aAlertText, contentIntent);
- }
-
- public static void alertsProgressListener_OnProgress(String aAlertName, long aProgress, long aProgressMax, String aAlertText) {
- int notificationID = aAlertName.hashCode();
- sNotificationClient.update(notificationID, aProgress, aProgressMax, aAlertText);
- }
-
- public static void closeNotification(String aAlertName) {
- String alertCookie = mAlertCookies.get(aAlertName);
- if (alertCookie != null) {
- callObserver(aAlertName, "alertfinished", alertCookie);
- mAlertCookies.remove(aAlertName);
- }
-
- removeObserver(aAlertName);
-
- int notificationID = aAlertName.hashCode();
- sNotificationClient.remove(notificationID);
- }
-
- public static void handleNotification(String aAction, String aAlertName, String aAlertCookie) {
- int notificationID = aAlertName.hashCode();
-
- if (GeckoApp.ACTION_ALERT_CALLBACK.equals(aAction)) {
- callObserver(aAlertName, "alertclickcallback", aAlertCookie);
-
- if (sNotificationClient.isOngoing(notificationID)) {
- // When clicked, keep the notification if it displays progress
- return;
- }
- }
-
- // Also send a notification to the observer service
- // New listeners should register for these notifications since they will be called even if
- // Gecko has been killed and restared between when your notification was shown and when the
- // user clicked on it.
- sendEventToGecko(GeckoEvent.createBroadcastEvent("Notification:Clicked", aAlertCookie));
- closeNotification(aAlertName);
- }
-
- public static int getDpi() {
- if (sDensityDpi == 0) {
- sDensityDpi = getContext().getResources().getDisplayMetrics().densityDpi;
- }
-
- return sDensityDpi;
- }
-
- public static void setFullScreen(boolean fullscreen) {
- if (getGeckoInterface() != null)
- getGeckoInterface().setFullScreen(fullscreen);
- }
-
- public static String showFilePickerForExtensions(String aExtensions) {
- if (getGeckoInterface() != null)
- return sActivityHelper.showFilePicker(getGeckoInterface().getActivity(), getMimeTypeFromExtensions(aExtensions));
- return "";
- }
-
- public static String showFilePickerForMimeType(String aMimeType) {
- if (getGeckoInterface() != null)
- return sActivityHelper.showFilePicker(getGeckoInterface().getActivity(), aMimeType);
- return "";
- }
-
- public static void performHapticFeedback(boolean aIsLongPress) {
- // Don't perform haptic feedback if a vibration is currently playing,
- // because the haptic feedback will nuke the vibration.
- if (!sVibrationMaybePlaying || System.nanoTime() >= sVibrationEndTime) {
- LayerView layerView = getLayerView();
- layerView.performHapticFeedback(aIsLongPress ?
- HapticFeedbackConstants.LONG_PRESS :
- HapticFeedbackConstants.VIRTUAL_KEY);
- }
- }
-
- private static Vibrator vibrator() {
- LayerView layerView = getLayerView();
- return (Vibrator) layerView.getContext().getSystemService(Context.VIBRATOR_SERVICE);
- }
-
- public static void vibrate(long milliseconds) {
- sVibrationEndTime = System.nanoTime() + milliseconds * 1000000;
- sVibrationMaybePlaying = true;
- vibrator().vibrate(milliseconds);
- }
-
- public static void vibrate(long[] pattern, int repeat) {
- // If pattern.length is even, the last element in the pattern is a
- // meaningless delay, so don't include it in vibrationDuration.
- long vibrationDuration = 0;
- int iterLen = pattern.length - (pattern.length % 2 == 0 ? 1 : 0);
- for (int i = 0; i < iterLen; i++) {
- vibrationDuration += pattern[i];
- }
-
- sVibrationEndTime = System.nanoTime() + vibrationDuration * 1000000;
- sVibrationMaybePlaying = true;
- vibrator().vibrate(pattern, repeat);
- }
-
- public static void cancelVibrate() {
- sVibrationMaybePlaying = false;
- sVibrationEndTime = 0;
- vibrator().cancel();
- }
-
- public static void showInputMethodPicker() {
- InputMethodManager imm = (InputMethodManager)
- getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
- imm.showInputMethodPicker();
- }
-
- public static void setKeepScreenOn(final boolean on) {
- ThreadUtils.postToUiThread(new Runnable() {
- @Override
- public void run() {
- // TODO
- }
- });
- }
-
- public static void notifyDefaultPrevented(final boolean defaultPrevented) {
- ThreadUtils.postToUiThread(new Runnable() {
- @Override
- public void run() {
- LayerView view = getLayerView();
- PanZoomController controller = (view == null ? null : view.getPanZoomController());
- if (controller != null) {
- controller.notifyDefaultActionPrevented(defaultPrevented);
- }
- }
- });
- }
-
- public static boolean isNetworkLinkUp() {
- ConnectivityManager cm = (ConnectivityManager)
- getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
- NetworkInfo info = cm.getActiveNetworkInfo();
- if (info == null || !info.isConnected())
- return false;
- return true;
- }
-
- public static boolean isNetworkLinkKnown() {
- ConnectivityManager cm = (ConnectivityManager)
- getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
- if (cm.getActiveNetworkInfo() == null)
- return false;
- return true;
- }
-
- public static void setSelectedLocale(String localeCode) {
- /* Bug 713464: This method is still called from Gecko side.
- Earlier we had an option to run Firefox in a language other than system's language.
- However, this is not supported as of now.
- Gecko resets the locale to en-US by calling this function with an empty string.
- This affects GeckoPreferences activity in multi-locale builds.
-
- //We're not using this, not need to save it (see bug 635342)
- SharedPreferences settings =
- getContext().getPreferences(Activity.MODE_PRIVATE);
- settings.edit().putString(getContext().getPackageName() + ".locale",
- localeCode).commit();
- Locale locale;
- int index;
- if ((index = localeCode.indexOf('-')) != -1 ||
- (index = localeCode.indexOf('_')) != -1) {
- String langCode = localeCode.substring(0, index);
- String countryCode = localeCode.substring(index + 1);
- locale = new Locale(langCode, countryCode);
- } else {
- locale = new Locale(localeCode);
- }
- Locale.setDefault(locale);
-
- Resources res = getContext().getBaseContext().getResources();
- Configuration config = res.getConfiguration();
- config.locale = locale;
- res.updateConfiguration(config, res.getDisplayMetrics());
- */
- }
-
- public static int[] getSystemColors() {
- // attrsAppearance[] must correspond to AndroidSystemColors structure in android/AndroidBridge.h
- final int[] attrsAppearance = {
- android.R.attr.textColor,
- android.R.attr.textColorPrimary,
- android.R.attr.textColorPrimaryInverse,
- android.R.attr.textColorSecondary,
- android.R.attr.textColorSecondaryInverse,
- android.R.attr.textColorTertiary,
- android.R.attr.textColorTertiaryInverse,
- android.R.attr.textColorHighlight,
- android.R.attr.colorForeground,
- android.R.attr.colorBackground,
- android.R.attr.panelColorForeground,
- android.R.attr.panelColorBackground
- };
-
- int[] result = new int[attrsAppearance.length];
-
- final ContextThemeWrapper contextThemeWrapper =
- new ContextThemeWrapper(getContext(), android.R.style.TextAppearance);
-
- final TypedArray appearance = contextThemeWrapper.getTheme().obtainStyledAttributes(attrsAppearance);
-
- if (appearance != null) {
- for (int i = 0; i < appearance.getIndexCount(); i++) {
- int idx = appearance.getIndex(i);
- int color = appearance.getColor(idx, 0);
- result[idx] = color;
- }
- appearance.recycle();
- }
-
- return result;
- }
-
- public static void killAnyZombies() {
- GeckoProcessesVisitor visitor = new GeckoProcessesVisitor() {
- @Override
- public boolean callback(int pid) {
- if (pid != android.os.Process.myPid())
- android.os.Process.killProcess(pid);
- return true;
- }
- };
-
- EnumerateGeckoProcesses(visitor);
- }
-
- public static boolean checkForGeckoProcs() {
-
- class GeckoPidCallback implements GeckoProcessesVisitor {
- public boolean otherPidExist = false;
- @Override
- public boolean callback(int pid) {
- if (pid != android.os.Process.myPid()) {
- otherPidExist = true;
- return false;
- }
- return true;
- }
- }
- GeckoPidCallback visitor = new GeckoPidCallback();
- EnumerateGeckoProcesses(visitor);
- return visitor.otherPidExist;
- }
-
- interface GeckoProcessesVisitor{
- boolean callback(int pid);
- }
-
- private static void EnumerateGeckoProcesses(GeckoProcessesVisitor visiter) {
- int pidColumn = -1;
- int userColumn = -1;
-
- try {
- // run ps and parse its output
- java.lang.Process ps = Runtime.getRuntime().exec("ps");
- BufferedReader in = new BufferedReader(new InputStreamReader(ps.getInputStream()),
- 2048);
-
- String headerOutput = in.readLine();
-
- // figure out the column offsets. We only care about the pid and user fields
- StringTokenizer st = new StringTokenizer(headerOutput);
-
- int tokenSoFar = 0;
- while (st.hasMoreTokens()) {
- String next = st.nextToken();
- if (next.equalsIgnoreCase("PID"))
- pidColumn = tokenSoFar;
- else if (next.equalsIgnoreCase("USER"))
- userColumn = tokenSoFar;
- tokenSoFar++;
- }
-
- // alright, the rest are process entries.
- String psOutput = null;
- while ((psOutput = in.readLine()) != null) {
- String[] split = psOutput.split("\\s+");
- if (split.length <= pidColumn || split.length <= userColumn)
- continue;
- int uid = android.os.Process.getUidForName(split[userColumn]);
- if (uid == android.os.Process.myUid() &&
- !split[split.length - 1].equalsIgnoreCase("ps")) {
- int pid = Integer.parseInt(split[pidColumn]);
- boolean keepGoing = visiter.callback(pid);
- if (keepGoing == false)
- break;
- }
- }
- in.close();
- }
- catch (Exception e) {
- Log.w(LOGTAG, "Failed to enumerate Gecko processes.", e);
- }
- }
-
- public static void waitForAnotherGeckoProc(){
- int countdown = 40;
- while (!checkForGeckoProcs() && --countdown > 0) {
- try {
- Thread.sleep(100);
- } catch (InterruptedException ie) {}
- }
- }
- public static String getAppNameByPID(int pid) {
- BufferedReader cmdlineReader = null;
- String path = "/proc/" + pid + "/cmdline";
- try {
- File cmdlineFile = new File(path);
- if (!cmdlineFile.exists())
- return "";
- cmdlineReader = new BufferedReader(new FileReader(cmdlineFile));
- return cmdlineReader.readLine().trim();
- } catch (Exception ex) {
- return "";
- } finally {
- if (null != cmdlineReader) {
- try {
- cmdlineReader.close();
- } catch (Exception e) {}
- }
- }
- }
-
- public static void listOfOpenFiles() {
- int pidColumn = -1;
- int nameColumn = -1;
-
- try {
- String filter = GeckoProfile.get(getContext()).getDir().toString();
- Log.i(LOGTAG, "[OPENFILE] Filter: " + filter);
-
- // run lsof and parse its output
- java.lang.Process lsof = Runtime.getRuntime().exec("lsof");
- BufferedReader in = new BufferedReader(new InputStreamReader(lsof.getInputStream()), 2048);
-
- String headerOutput = in.readLine();
- StringTokenizer st = new StringTokenizer(headerOutput);
- int token = 0;
- while (st.hasMoreTokens()) {
- String next = st.nextToken();
- if (next.equalsIgnoreCase("PID"))
- pidColumn = token;
- else if (next.equalsIgnoreCase("NAME"))
- nameColumn = token;
- token++;
- }
-
- // alright, the rest are open file entries.
- Map<Integer, String> pidNameMap = new TreeMap<Integer, String>();
- String output = null;
- while ((output = in.readLine()) != null) {
- String[] split = output.split("\\s+");
- if (split.length <= pidColumn || split.length <= nameColumn)
- continue;
- Integer pid = new Integer(split[pidColumn]);
- String name = pidNameMap.get(pid);
- if (name == null) {
- name = getAppNameByPID(pid.intValue());
- pidNameMap.put(pid, name);
- }
- String file = split[nameColumn];
- if (!TextUtils.isEmpty(name) && !TextUtils.isEmpty(file) && file.startsWith(filter))
- Log.i(LOGTAG, "[OPENFILE] " + name + "(" + split[pidColumn] + ") : " + file);
- }
- in.close();
- } catch (Exception e) { }
- }
-
- public static void scanMedia(String aFile, String aMimeType) {
- Context context = getContext();
- GeckoMediaScannerClient.startScan(context, aFile, aMimeType);
- }
-
- public static byte[] getIconForExtension(String aExt, int iconSize) {
- try {
- if (iconSize <= 0)
- iconSize = 16;
-
- if (aExt != null && aExt.length() > 1 && aExt.charAt(0) == '.')
- aExt = aExt.substring(1);
-
- PackageManager pm = getContext().getPackageManager();
- Drawable icon = getDrawableForExtension(pm, aExt);
- if (icon == null) {
- // Use a generic icon
- icon = pm.getDefaultActivityIcon();
- }
-
- Bitmap bitmap = ((BitmapDrawable)icon).getBitmap();
- if (bitmap.getWidth() != iconSize || bitmap.getHeight() != iconSize)
- bitmap = Bitmap.createScaledBitmap(bitmap, iconSize, iconSize, true);
-
- ByteBuffer buf = ByteBuffer.allocate(iconSize * iconSize * 4);
- bitmap.copyPixelsToBuffer(buf);
-
- return buf.array();
- }
- catch (Exception e) {
- Log.w(LOGTAG, "getIconForExtension failed.", e);
- return null;
- }
- }
-
- private static Drawable getDrawableForExtension(PackageManager pm, String aExt) {
- Intent intent = new Intent(Intent.ACTION_VIEW);
- MimeTypeMap mtm = MimeTypeMap.getSingleton();
- String mimeType = mtm.getMimeTypeFromExtension(aExt);
- if (mimeType != null && mimeType.length() > 0)
- intent.setType(mimeType);
- else
- return null;
-
- List<ResolveInfo> list = pm.queryIntentActivities(intent, 0);
- if (list.size() == 0)
- return null;
-
- ResolveInfo resolveInfo = list.get(0);
-
- if (resolveInfo == null)
- return null;
-
- ActivityInfo activityInfo = resolveInfo.activityInfo;
-
- return activityInfo.loadIcon(pm);
- }
-
- public static boolean getShowPasswordSetting() {
- try {
- int showPassword =
- Settings.System.getInt(getContext().getContentResolver(),
- Settings.System.TEXT_SHOW_PASSWORD, 1);
- return (showPassword > 0);
- }
- catch (Exception e) {
- return true;
- }
- }
-
- public static void addPluginView(View view,
- int x, int y,
- int w, int h,
- boolean isFullScreen) {
- if (getGeckoInterface() != null)
- getGeckoInterface().addPluginView(view, new Rect(x, y, x + w, y + h), isFullScreen);
- }
-
- public static void removePluginView(View view, boolean isFullScreen) {
- if (getGeckoInterface() != null)
- getGeckoInterface().removePluginView(view, isFullScreen);
- }
-
- /**
- * A plugin that wish to be loaded in the WebView must provide this permission
- * in their AndroidManifest.xml.
- */
- public static final String PLUGIN_ACTION = "android.webkit.PLUGIN";
- public static final String PLUGIN_PERMISSION = "android.webkit.permission.PLUGIN";
-
- private static final String PLUGIN_SYSTEM_LIB = "/system/lib/plugins/";
-
- private static final String PLUGIN_TYPE = "type";
- private static final String TYPE_NATIVE = "native";
- static public ArrayList<PackageInfo> mPackageInfoCache = new ArrayList<PackageInfo>();
-
- // Returns null if plugins are blocked on the device.
- static String[] getPluginDirectories() {
-
- // An awful hack to detect Tegra devices. Easiest way to do it without spinning up a EGL context.
- boolean isTegra = (new File("/system/lib/hw/gralloc.tegra.so")).exists() ||
- (new File("/system/lib/hw/gralloc.tegra3.so")).exists();
- if (isTegra) {
- // disable Flash on Tegra ICS with CM9 and other custom firmware (bug 736421)
- File vfile = new File("/proc/version");
- FileReader vreader = null;
- try {
- if (vfile.canRead()) {
- vreader = new FileReader(vfile);
- String version = new BufferedReader(vreader).readLine();
- if (version.indexOf("CM9") != -1 ||
- version.indexOf("cyanogen") != -1 ||
- version.indexOf("Nova") != -1)
- {
- Log.w(LOGTAG, "Blocking plugins because of Tegra 2 + unofficial ICS bug (bug 736421)");
- return null;
- }
- }
- } catch (IOException ex) {
- // nothing
- } finally {
- try {
- if (vreader != null) {
- vreader.close();
- }
- } catch (IOException ex) {
- // nothing
- }
- }
-
- // disable on KitKat
- if (Build.VERSION.SDK_INT >= 19) {
- Log.w(LOGTAG, "Blocking plugins because of Tegra OpenGL deadlocks");
- return null;
- }
- }
-
- ArrayList<String> directories = new ArrayList<String>();
- PackageManager pm = getContext().getPackageManager();
- List<ResolveInfo> plugins = pm.queryIntentServices(new Intent(PLUGIN_ACTION),
- PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
-
- synchronized(mPackageInfoCache) {
-
- // clear the list of existing packageInfo objects
- mPackageInfoCache.clear();
-
-
- for (ResolveInfo info : plugins) {
-
- // retrieve the plugin's service information
- ServiceInfo serviceInfo = info.serviceInfo;
- if (serviceInfo == null) {
- Log.w(LOGTAG, "Ignoring bad plugin.");
- continue;
- }
-
- // Blacklist HTC's flash lite.
- // See bug #704516 - We're not quite sure what Flash Lite does,
- // but loading it causes Flash to give errors and fail to draw.
- if (serviceInfo.packageName.equals("com.htc.flashliteplugin")) {
- Log.w(LOGTAG, "Skipping HTC's flash lite plugin");
- continue;
- }
-
-
- // Retrieve information from the plugin's manifest.
- PackageInfo pkgInfo;
- try {
- pkgInfo = pm.getPackageInfo(serviceInfo.packageName,
- PackageManager.GET_PERMISSIONS
- | PackageManager.GET_SIGNATURES);
- } catch (Exception e) {
- Log.w(LOGTAG, "Can't find plugin: " + serviceInfo.packageName);
- continue;
- }
-
- if (pkgInfo == null) {
- Log.w(LOGTAG, "Not loading plugin: " + serviceInfo.packageName + ". Could not load package information.");
- continue;
- }
-
- /*
- * find the location of the plugin's shared library. The default
- * is to assume the app is either a user installed app or an
- * updated system app. In both of these cases the library is
- * stored in the app's data directory.
- */
- String directory = pkgInfo.applicationInfo.dataDir + "/lib";
- final int appFlags = pkgInfo.applicationInfo.flags;
- final int updatedSystemFlags = ApplicationInfo.FLAG_SYSTEM |
- ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
-
- // preloaded system app with no user updates
- if ((appFlags & updatedSystemFlags) == ApplicationInfo.FLAG_SYSTEM) {
- directory = PLUGIN_SYSTEM_LIB + pkgInfo.packageName;
- }
-
- // check if the plugin has the required permissions
- String permissions[] = pkgInfo.requestedPermissions;
- if (permissions == null) {
- Log.w(LOGTAG, "Not loading plugin: " + serviceInfo.packageName + ". Does not have required permission.");
- continue;
- }
- boolean permissionOk = false;
- for (String permit : permissions) {
- if (PLUGIN_PERMISSION.equals(permit)) {
- permissionOk = true;
- break;
- }
- }
- if (!permissionOk) {
- Log.w(LOGTAG, "Not loading plugin: " + serviceInfo.packageName + ". Does not have required permission (2).");
- continue;
- }
-
- // check to ensure the plugin is properly signed
- Signature signatures[] = pkgInfo.signatures;
- if (signatures == null) {
- Log.w(LOGTAG, "Not loading plugin: " + serviceInfo.packageName + ". Not signed.");
- continue;
- }
-
- // determine the type of plugin from the manifest
- if (serviceInfo.metaData == null) {
- Log.e(LOGTAG, "The plugin '" + serviceInfo.name + "' has no defined type.");
- continue;
- }
-
- String pluginType = serviceInfo.metaData.getString(PLUGIN_TYPE);
- if (!TYPE_NATIVE.equals(pluginType)) {
- Log.e(LOGTAG, "Unrecognized plugin type: " + pluginType);
- continue;
- }
-
- try {
- Class<?> cls = getPluginClass(serviceInfo.packageName, serviceInfo.name);
-
- //TODO implement any requirements of the plugin class here!
- boolean classFound = true;
-
- if (!classFound) {
- Log.e(LOGTAG, "The plugin's class' " + serviceInfo.name + "' does not extend the appropriate class.");
- continue;
- }
-
- } catch (NameNotFoundException e) {
- Log.e(LOGTAG, "Can't find plugin: " + serviceInfo.packageName);
- continue;
- } catch (ClassNotFoundException e) {
- Log.e(LOGTAG, "Can't find plugin's class: " + serviceInfo.name);
- continue;
- }
-
- // if all checks have passed then make the plugin available
- mPackageInfoCache.add(pkgInfo);
- directories.add(directory);
- }
- }
-
- return directories.toArray(new String[directories.size()]);
- }
-
- static String getPluginPackage(String pluginLib) {
-
- if (pluginLib == null || pluginLib.length() == 0) {
- return null;
- }
-
- synchronized(mPackageInfoCache) {
- for (PackageInfo pkgInfo : mPackageInfoCache) {
- if (pluginLib.contains(pkgInfo.packageName)) {
- return pkgInfo.packageName;
- }
- }
- }
-
- return null;
- }
-
- static Class<?> getPluginClass(String packageName, String className)
- throws NameNotFoundException, ClassNotFoundException {
- Context pluginContext = getContext().createPackageContext(packageName,
- Context.CONTEXT_INCLUDE_CODE |
- Context.CONTEXT_IGNORE_SECURITY);
- ClassLoader pluginCL = pluginContext.getClassLoader();
- return pluginCL.loadClass(className);
- }
-
- public static Class<?> loadPluginClass(String className, String libName) {
- if (getGeckoInterface() == null)
- return null;
- try {
- final String packageName = getPluginPackage(libName);
- final int contextFlags = Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY;
- final Context pluginContext = getContext().createPackageContext(packageName, contextFlags);
- return pluginContext.getClassLoader().loadClass(className);
- } catch (java.lang.ClassNotFoundException cnfe) {
- Log.w(LOGTAG, "Couldn't find plugin class " + className, cnfe);
- return null;
- } catch (android.content.pm.PackageManager.NameNotFoundException nnfe) {
- Log.w(LOGTAG, "Couldn't find package.", nnfe);
- return null;
- }
- }
-
- private static ContextGetter sContextGetter;
-
- public static Context getContext() {
- return sContextGetter.getContext();
- }
-
- public static void setContextGetter(ContextGetter cg) {
- sContextGetter = cg;
- }
-
- public interface AppStateListener {
- public void onPause();
- public void onResume();
- public void onOrientationChanged();
- }
-
- public interface GeckoInterface {
- public GeckoProfile getProfile();
- public PromptService getPromptService();
- public Activity getActivity();
- public String getDefaultUAString();
- public LocationListener getLocationListener();
- public SensorEventListener getSensorEventListener();
- public void doRestart();
- public void setFullScreen(boolean fullscreen);
- public void addPluginView(View view, final Rect rect, final boolean isFullScreen);
- public void removePluginView(final View view, final boolean isFullScreen);
- public void enableCameraView();
- public void disableCameraView();
- public void addAppStateListener(AppStateListener listener);
- public void removeAppStateListener(AppStateListener listener);
- public View getCameraView();
- public void notifyWakeLockChanged(String topic, String state);
- public FormAssistPopup getFormAssistPopup();
- public boolean areTabsShown();
- public AbsoluteLayout getPluginContainer();
- public void notifyCheckUpdateResult(String result);
- public boolean hasTabsSideBar();
- public void invalidateOptionsMenu();
- };
-
- private static GeckoInterface sGeckoInterface;
-
- public static GeckoInterface getGeckoInterface() {
- return sGeckoInterface;
- }
-
- public static void setGeckoInterface(GeckoInterface aGeckoInterface) {
- sGeckoInterface = aGeckoInterface;
- }
-
- public static android.hardware.Camera sCamera = null;
-
- static native void cameraCallbackBridge(byte[] data);
-
- static int kPreferedFps = 25;
- static byte[] sCameraBuffer = null;
-
- static int[] initCamera(String aContentType, int aCamera, int aWidth, int aHeight) {
- ThreadUtils.postToUiThread(new Runnable() {
- @Override
- public void run() {
- try {
- if (getGeckoInterface() != null)
- getGeckoInterface().enableCameraView();
- } catch (Exception e) {}
- }
- });
-
- // [0] = 0|1 (failure/success)
- // [1] = width
- // [2] = height
- // [3] = fps
- int[] result = new int[4];
- result[0] = 0;
-
- if (Build.VERSION.SDK_INT >= 9) {
- if (android.hardware.Camera.getNumberOfCameras() == 0)
- return result;
- }
-
- try {
- // no front/back camera before API level 9
- if (Build.VERSION.SDK_INT >= 9)
- sCamera = android.hardware.Camera.open(aCamera);
- else
- sCamera = android.hardware.Camera.open();
-
- android.hardware.Camera.Parameters params = sCamera.getParameters();
- params.setPreviewFormat(ImageFormat.NV21);
-
- // use the preview fps closest to 25 fps.
- int fpsDelta = 1000;
- try {
- Iterator<Integer> it = params.getSupportedPreviewFrameRates().iterator();
- while (it.hasNext()) {
- int nFps = it.next();
- if (Math.abs(nFps - kPreferedFps) < fpsDelta) {
- fpsDelta = Math.abs(nFps - kPreferedFps);
- params.setPreviewFrameRate(nFps);
- }
- }
- } catch(Exception e) {
- params.setPreviewFrameRate(kPreferedFps);
- }
-
- // set up the closest preview size available
- Iterator<android.hardware.Camera.Size> sit = params.getSupportedPreviewSizes().iterator();
- int sizeDelta = 10000000;
- int bufferSize = 0;
- while (sit.hasNext()) {
- android.hardware.Camera.Size size = sit.next();
- if (Math.abs(size.width * size.height - aWidth * aHeight) < sizeDelta) {
- sizeDelta = Math.abs(size.width * size.height - aWidth * aHeight);
- params.setPreviewSize(size.width, size.height);
- bufferSize = size.width * size.height;
- }
- }
-
- try {
- if (getGeckoInterface() != null) {
- View cameraView = getGeckoInterface().getCameraView();
- if (cameraView instanceof SurfaceView) {
- sCamera.setPreviewDisplay(((SurfaceView)cameraView).getHolder());
- } else if (cameraView instanceof TextureView) {
- sCamera.setPreviewTexture(((TextureView)cameraView).getSurfaceTexture());
- }
- }
- } catch(IOException e) {
- Log.w(LOGTAG, "Error setPreviewXXX:", e);
- } catch(RuntimeException e) {
- Log.w(LOGTAG, "Error setPreviewXXX:", e);
- }
-
- sCamera.setParameters(params);
- sCameraBuffer = new byte[(bufferSize * 12) / 8];
- sCamera.addCallbackBuffer(sCameraBuffer);
- sCamera.setPreviewCallbackWithBuffer(new android.hardware.Camera.PreviewCallback() {
- @Override
- public void onPreviewFrame(byte[] data, android.hardware.Camera camera) {
- cameraCallbackBridge(data);
- if (sCamera != null)
- sCamera.addCallbackBuffer(sCameraBuffer);
- }
- });
- sCamera.startPreview();
- params = sCamera.getParameters();
- result[0] = 1;
- result[1] = params.getPreviewSize().width;
- result[2] = params.getPreviewSize().height;
- result[3] = params.getPreviewFrameRate();
- } catch(RuntimeException e) {
- Log.w(LOGTAG, "initCamera RuntimeException.", e);
- result[0] = result[1] = result[2] = result[3] = 0;
- }
- return result;
- }
-
- static synchronized void closeCamera() {
- ThreadUtils.postToUiThread(new Runnable() {
- @Override
- public void run() {
- try {
- if (getGeckoInterface() != null)
- getGeckoInterface().disableCameraView();
- } catch (Exception e) {}
- }
- });
- if (sCamera != null) {
- sCamera.stopPreview();
- sCamera.release();
- sCamera = null;
- sCameraBuffer = null;
- }
- }
-
- /**
- * Adds a listener for a gecko event.
- * This method is thread-safe and may be called at any time. In particular, calling it
- * with an event that is currently being processed has the properly-defined behaviour that
- * any added listeners will not be invoked on the event currently being processed, but
- * will be invoked on future events of that type.
- *
- * This method is referenced by Robocop via reflection.
- */
- public static void registerEventListener(String event, GeckoEventListener listener) {
- sEventDispatcher.registerEventListener(event, listener);
- }
-
- static EventDispatcher getEventDispatcher() {
- return sEventDispatcher;
- }
-
- /**
- * Remove a previously-registered listener for a gecko event.
- * This method is thread-safe and may be called at any time. In particular, calling it
- * with an event that is currently being processed has the properly-defined behaviour that
- * any removed listeners will still be invoked on the event currently being processed, but
- * will not be invoked on future events of that type.
- *
- * This method is referenced by Robocop via reflection.
- */
- public static void unregisterEventListener(String event, GeckoEventListener listener) {
- sEventDispatcher.unregisterEventListener(event, listener);
- }
-
- /*
- * Battery API related methods.
- */
- public static void enableBatteryNotifications() {
- GeckoBatteryManager.enableNotifications();
- }
-
- public static String handleGeckoMessage(String message) {
- return sEventDispatcher.dispatchEvent(message);
- }
-
- public static void disableBatteryNotifications() {
- GeckoBatteryManager.disableNotifications();
- }
-
- public static double[] getCurrentBatteryInformation() {
- return GeckoBatteryManager.getCurrentInformation();
- }
-
- static void checkUriVisited(String uri) { // invoked from native JNI code
- GlobalHistory.getInstance().checkUriVisited(uri);
- }
-
- static void markUriVisited(final String uri) { // invoked from native JNI code
- ThreadUtils.postToBackgroundThread(new Runnable() {
- @Override
- public void run() {
- GlobalHistory.getInstance().add(uri);
- }
- });
- }
-
- static void setUriTitle(final String uri, final String title) { // invoked from native JNI code
- ThreadUtils.postToBackgroundThread(new Runnable() {
- @Override
- public void run() {
- GlobalHistory.getInstance().update(uri, title);
- }
- });
- }
-
- static void hideProgressDialog() {
- // unused stub
- }
-
- /*
- * WebSMS related methods.
- */
- public static void sendMessage(String aNumber, String aMessage, int aRequestId) {
- if (SmsManager.getInstance() == null) {
- return;
- }
-
- SmsManager.getInstance().send(aNumber, aMessage, aRequestId);
- }
-
- public static void getMessage(int aMessageId, int aRequestId) {
- if (SmsManager.getInstance() == null) {
- return;
- }
-
- SmsManager.getInstance().getMessage(aMessageId, aRequestId);
- }
-
- public static void deleteMessage(int aMessageId, int aRequestId) {
- if (SmsManager.getInstance() == null) {
- return;
- }
-
- SmsManager.getInstance().deleteMessage(aMessageId, aRequestId);
- }
-
- public static void createMessageList(long aStartDate, long aEndDate, String[] aNumbers, int aNumbersCount, int aDeliveryState, boolean aReverse, int aRequestId) {
- if (SmsManager.getInstance() == null) {
- return;
- }
-
- SmsManager.getInstance().createMessageList(aStartDate, aEndDate, aNumbers, aNumbersCount, aDeliveryState, aReverse, aRequestId);
- }
-
- public static void getNextMessageInList(int aListId, int aRequestId) {
- if (SmsManager.getInstance() == null) {
- return;
- }
-
- SmsManager.getInstance().getNextMessageInList(aListId, aRequestId);
- }
-
- public static void clearMessageList(int aListId) {
- if (SmsManager.getInstance() == null) {
- return;
- }
-
- SmsManager.getInstance().clearMessageList(aListId);
- }
-
- /* Called by JNI from AndroidBridge, and by reflection from tests/BaseTest.java.in */
- public static boolean isTablet() {
- return HardwareUtils.isTablet();
- }
-
- public static void viewSizeChanged() {
- LayerView v = getLayerView();
- if (v != null && v.isIMEEnabled()) {
- sendEventToGecko(GeckoEvent.createBroadcastEvent(
- "ScrollTo:FocusedInput", ""));
- }
- }
-
- public static double[] getCurrentNetworkInformation() {
- return GeckoNetworkManager.getInstance().getCurrentInformation();
- }
-
- public static void enableNetworkNotifications() {
- GeckoNetworkManager.getInstance().enableNotifications();
- }
-
- public static void disableNetworkNotifications() {
- GeckoNetworkManager.getInstance().disableNotifications();
- }
-
- // values taken from android's Base64
- public static final int BASE64_DEFAULT = 0;
- public static final int BASE64_URL_SAFE = 8;
-
- /**
- * taken from http://www.source-code.biz/base64coder/java/Base64Coder.java.txt and modified (MIT License)
- */
- // Mapping table from 6-bit nibbles to Base64 characters.
- private static final byte[] map1 = new byte[64];
- private static final byte[] map1_urlsafe;
- static {
- int i=0;
- for (byte c='A'; c<='Z'; c++) map1[i++] = c;
- for (byte c='a'; c<='z'; c++) map1[i++] = c;
- for (byte c='0'; c<='9'; c++) map1[i++] = c;
- map1[i++] = '+'; map1[i++] = '/';
- map1_urlsafe = map1.clone();
- map1_urlsafe[62] = '-'; map1_urlsafe[63] = '_';
- }
-
- // Mapping table from Base64 characters to 6-bit nibbles.
- private static final byte[] map2 = new byte[128];
- static {
- for (int i=0; i<map2.length; i++) map2[i] = -1;
- for (int i=0; i<64; i++) map2[map1[i]] = (byte)i;
- map2['-'] = (byte)62; map2['_'] = (byte)63;
- }
-
- final static byte EQUALS_ASCII = (byte) '=';
-
- /**
- * Encodes a byte array into Base64 format.
- * No blanks or line breaks are inserted in the output.
- * @param in An array containing the data bytes to be encoded.
- * @return A character array containing the Base64 encoded data.
- */
- public static byte[] encodeBase64(byte[] in, int flags) {
- if (Build.VERSION.SDK_INT >=Build.VERSION_CODES.FROYO)
- return Base64.encode(in, flags | Base64.NO_WRAP);
- int oDataLen = (in.length*4+2)/3; // output length without padding
- int oLen = ((in.length+2)/3)*4; // output length including padding
- byte[] out = new byte[oLen];
- int ip = 0;
- int iEnd = in.length;
- int op = 0;
- byte[] toMap = ((flags & BASE64_URL_SAFE) == 0 ? map1 : map1_urlsafe);
- while (ip < iEnd) {
- int i0 = in[ip++] & 0xff;
- int i1 = ip < iEnd ? in[ip++] & 0xff : 0;
- int i2 = ip < iEnd ? in[ip++] & 0xff : 0;
- int o0 = i0 >>> 2;
- int o1 = ((i0 & 3) << 4) | (i1 >>> 4);
- int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6);
- int o3 = i2 & 0x3F;
- out[op++] = toMap[o0];
- out[op++] = toMap[o1];
- out[op] = op < oDataLen ? toMap[o2] : EQUALS_ASCII; op++;
- out[op] = op < oDataLen ? toMap[o3] : EQUALS_ASCII; op++;
- }
- return out;
- }
-
- /**
- * Decodes a byte array from Base64 format.
- * No blanks or line breaks are allowed within the Base64 encoded input data.
- * @param in A character array containing the Base64 encoded data.
- * @param iOff Offset of the first character in <code>in</code> to be processed.
- * @param iLen Number of characters to process in <code>in</code>, starting at <code>iOff</code>.
- * @return An array containing the decoded data bytes.
- * @throws IllegalArgumentException If the input is not valid Base64 encoded data.
- */
- public static byte[] decodeBase64(byte[] in, int flags) {
- if (Build.VERSION.SDK_INT >=Build.VERSION_CODES.FROYO)
- return Base64.decode(in, flags);
- int iOff = 0;
- int iLen = in.length;
- if (iLen%4 != 0) throw new IllegalArgumentException ("Length of Base64 encoded input string is not a multiple of 4.");
- while (iLen > 0 && in[iOff+iLen-1] == '=') iLen--;
- int oLen = (iLen*3) / 4;
- byte[] out = new byte[oLen];
- int ip = iOff;
- int iEnd = iOff + iLen;
- int op = 0;
- while (ip < iEnd) {
- int i0 = in[ip++];
- int i1 = in[ip++];
- int i2 = ip < iEnd ? in[ip++] : 'A';
- int i3 = ip < iEnd ? in[ip++] : 'A';
- if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127)
- throw new IllegalArgumentException ("Illegal character in Base64 encoded data.");
- int b0 = map2[i0];
- int b1 = map2[i1];
- int b2 = map2[i2];
- int b3 = map2[i3];
- if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0)
- throw new IllegalArgumentException ("Illegal character in Base64 encoded data.");
- int o0 = ( b0 <<2) | (b1>>>4);
- int o1 = ((b1 & 0xf)<<4) | (b2>>>2);
- int o2 = ((b2 & 3)<<6) | b3;
- out[op++] = (byte)o0;
- if (op<oLen) out[op++] = (byte)o1;
- if (op<oLen) out[op++] = (byte)o2; }
- return out;
- }
-
- public static byte[] decodeBase64(String s, int flags) {
- return decodeBase64(s.getBytes(), flags);
- }
-
- public static short getScreenOrientation() {
- return GeckoScreenOrientationListener.getInstance().getScreenOrientation();
- }
-
- public static void enableScreenOrientationNotifications() {
- GeckoScreenOrientationListener.getInstance().enableNotifications();
- }
-
- public static void disableScreenOrientationNotifications() {
- GeckoScreenOrientationListener.getInstance().disableNotifications();
- }
-
- public static void lockScreenOrientation(int aOrientation) {
- GeckoScreenOrientationListener.getInstance().lockScreenOrientation(aOrientation);
- }
-
- public static void unlockScreenOrientation() {
- GeckoScreenOrientationListener.getInstance().unlockScreenOrientation();
- }
-
- public static boolean pumpMessageLoop() {
- MessageQueue mq = Looper.myQueue();
- Message msg = getNextMessageFromQueue(mq);
- if (msg == null)
- return false;
- if (msg.getTarget() == null)
- Looper.myLooper().quit();
- else
- msg.getTarget().dispatchMessage(msg);
-
- try {
- msg.recycle();
- } catch (IllegalStateException e) {
- // There is nothing we can do here so just eat it
- }
- return true;
- }
-
- static native void notifyFilePickerResult(String filePath, long id);
-
- public static void showFilePickerAsync(String aMimeType, final long id) {
- sActivityHelper.showFilePickerAsync(getGeckoInterface().getActivity(), aMimeType, new ActivityHandlerHelper.FileResultHandler() {
- public void gotFile(String filename) {
- GeckoAppShell.notifyFilePickerResult(filename, id);
- }
- });
- }
-
- public static void notifyWakeLockChanged(String topic, String state) {
- if (getGeckoInterface() != null)
- getGeckoInterface().notifyWakeLockChanged(topic, state);
- }
-
- public static String getGfxInfoData() {
- return GfxInfoThread.getData();
- }
-
- public static void registerSurfaceTextureFrameListener(Object surfaceTexture, final int id) {
- ((SurfaceTexture)surfaceTexture).setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() {
- @Override
- public void onFrameAvailable(SurfaceTexture surfaceTexture) {
- GeckoAppShell.onSurfaceTextureFrameAvailable(surfaceTexture, id);
- }
- });
- }
-
- public static void unregisterSurfaceTextureFrameListener(Object surfaceTexture) {
- ((SurfaceTexture)surfaceTexture).setOnFrameAvailableListener(null);
- }
-
- public static boolean unlockProfile() {
- // Try to kill any zombie Fennec's that might be running
- GeckoAppShell.killAnyZombies();
-
- // Then force unlock this profile
- if (getGeckoInterface() != null) {
- GeckoProfile profile = getGeckoInterface().getProfile();
- File lock = profile.getFile(".parentlock");
- return lock.exists() && lock.delete();
- }
- return false;
- }
-
- public static String getProxyForURI(String spec, String scheme, String host, int port) {
- URI uri = null;
- try {
- uri = new URI(spec);
- } catch(java.net.URISyntaxException uriEx) {
- try {
- uri = new URI(scheme, null, host, port, null, null, null);
- } catch(java.net.URISyntaxException uriEx2) {
- Log.d("GeckoProxy", "Failed to create uri from spec", uriEx);
- Log.d("GeckoProxy", "Failed to create uri from parts", uriEx2);
- }
- }
- if (uri != null) {
- ProxySelector ps = ProxySelector.getDefault();
- if (ps != null) {
- List<Proxy> proxies = ps.select(uri);
- if (proxies != null && !proxies.isEmpty()) {
- Proxy proxy = proxies.get(0);
- if (!Proxy.NO_PROXY.equals(proxy)) {
- final String proxyStr;
- switch (proxy.type()) {
- case HTTP:
- proxyStr = "PROXY " + proxy.address().toString();
- break;
- case SOCKS:
- proxyStr = "SOCKS " + proxy.address().toString();
- break;
- case DIRECT:
- default:
- proxyStr = "DIRECT";
- break;
- }
- return proxyStr;
- }
- }
- }
- }
- return "DIRECT";
- }
-}
diff --git a/mobile/android/base/GeckoApplication.java b/mobile/android/base/GeckoApplication.java
deleted file mode 100644
index fa6d44b3d..000000000
--- a/mobile/android/base/GeckoApplication.java
+++ /dev/null
@@ -1,112 +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/. */
-
-package org.mozilla.gecko;
-
-import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.db.BrowserDB;
-import org.mozilla.gecko.mozglue.GeckoLoader;
-import org.mozilla.gecko.util.Clipboard;
-import org.mozilla.gecko.util.HardwareUtils;
-import org.mozilla.gecko.util.ThreadUtils;
-
-import android.app.Application;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-
-public class GeckoApplication extends Application {
-
- private boolean mInited;
- private boolean mInBackground;
- private boolean mPausedGecko;
- private boolean mNeedsRestart;
-
- private LightweightTheme mLightweightTheme;
-
- protected void initialize() {
- if (mInited)
- return;
-
- // workaround for http://code.google.com/p/android/issues/detail?id=20915
- try {
- Class.forName("android.os.AsyncTask");
- } catch (ClassNotFoundException e) {}
-
- mLightweightTheme = new LightweightTheme(this);
-
- GeckoConnectivityReceiver.getInstance().init(getApplicationContext());
- GeckoBatteryManager.getInstance().init(getApplicationContext());
- GeckoBatteryManager.getInstance().start();
- GeckoNetworkManager.getInstance().init(getApplicationContext());
- MemoryMonitor.getInstance().init(getApplicationContext());
-
- BroadcastReceiver receiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- mNeedsRestart = true;
- }
- };
- registerReceiver(receiver, new IntentFilter(Intent.ACTION_LOCALE_CHANGED));
-
- mInited = true;
- }
-
- protected void onActivityPause(GeckoActivityStatus activity) {
- mInBackground = true;
-
- if ((activity.isFinishing() == false) &&
- (activity.isGeckoActivityOpened() == false)) {
- // Notify Gecko that we are pausing; the cache service will be
- // shutdown, closing the disk cache cleanly. If the android
- // low memory killer subsequently kills us, the disk cache will
- // be left in a consistent state, avoiding costly cleanup and
- // re-creation.
- GeckoAppShell.sendEventToGecko(GeckoEvent.createAppBackgroundingEvent());
- mPausedGecko = true;
-
- ThreadUtils.postToBackgroundThread(new Runnable() {
- @Override
- public void run() {
- BrowserDB.expireHistory(getContentResolver(),
- BrowserContract.ExpirePriority.NORMAL);
- }
- });
- }
- GeckoConnectivityReceiver.getInstance().stop();
- GeckoNetworkManager.getInstance().stop();
- }
-
- protected void onActivityResume(GeckoActivityStatus activity) {
- if (mPausedGecko) {
- GeckoAppShell.sendEventToGecko(GeckoEvent.createAppForegroundingEvent());
- mPausedGecko = false;
- }
- GeckoConnectivityReceiver.getInstance().start();
- GeckoNetworkManager.getInstance().start();
-
- mInBackground = false;
- }
-
- protected boolean needsRestart() {
- return mNeedsRestart;
- }
-
- @Override
- public void onCreate() {
- HardwareUtils.init(getApplicationContext());
- Clipboard.init(getApplicationContext());
- GeckoLoader.loadMozGlue(getApplicationContext());
- super.onCreate();
- }
-
- public boolean isApplicationInBackground() {
- return mInBackground;
- }
-
- public LightweightTheme getLightweightTheme() {
- return mLightweightTheme;
- }
-}
diff --git a/mobile/android/base/GeckoBatteryManager.java b/mobile/android/base/GeckoBatteryManager.java
deleted file mode 100644
index 85e7bd22c..000000000
--- a/mobile/android/base/GeckoBatteryManager.java
+++ /dev/null
@@ -1,193 +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.gecko;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.BatteryManager;
-import android.os.Build;
-import android.os.SystemClock;
-import android.util.Log;
-
-public class GeckoBatteryManager extends BroadcastReceiver {
- private static final String LOGTAG = "GeckoBatteryManager";
-
- // Those constants should be keep in sync with the ones in:
- // dom/battery/Constants.h
- private final static double kDefaultLevel = 1.0;
- private final static boolean kDefaultCharging = true;
- private final static double kDefaultRemainingTime = 0.0;
- private final static double kUnknownRemainingTime = -1.0;
-
- private static long sLastLevelChange = 0;
- private static boolean sNotificationsEnabled = false;
- private static double sLevel = kDefaultLevel;
- private static boolean sCharging = kDefaultCharging;
- private static double sRemainingTime = kDefaultRemainingTime;
-
- private static GeckoBatteryManager sInstance = new GeckoBatteryManager();
-
- private IntentFilter mFilter;
- private Context mApplicationContext;
- private boolean mIsEnabled;
-
- public static GeckoBatteryManager getInstance() {
- return sInstance;
- }
-
- private GeckoBatteryManager() {
- mFilter = new IntentFilter();
- mFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
- }
-
- public void init(Context context) {
- mApplicationContext = context.getApplicationContext();
- }
-
- public synchronized void start() {
- if (!mIsEnabled) {
- // registerReceiver will return null if registering fails
- if (mApplicationContext.registerReceiver(this, mFilter) == null) {
- Log.e(LOGTAG, "Registering receiver failed");
- } else {
- mIsEnabled = true;
- }
- }
- }
-
- public synchronized void stop() {
- if (mIsEnabled) {
- mApplicationContext.unregisterReceiver(this);
- mIsEnabled = false;
- }
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (!intent.getAction().equals(Intent.ACTION_BATTERY_CHANGED)) {
- Log.e(LOGTAG, "Got an unexpected intent!");
- return;
- }
-
- boolean previousCharging = isCharging();
- double previousLevel = getLevel();
-
- // NOTE: it might not be common (in 2012) but technically, Android can run
- // on a device that has no battery so we want to make sure it's not the case
- // before bothering checking for battery state.
- // However, the Galaxy Nexus phone advertizes itself as battery-less which
- // force us to special-case the logic.
- // See the Google bug: https://code.google.com/p/android/issues/detail?id=22035
- if (intent.getBooleanExtra(BatteryManager.EXTRA_PRESENT, false) ||
- Build.MODEL.equals("Galaxy Nexus")) {
- int plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
- if (plugged == -1) {
- sCharging = kDefaultCharging;
- Log.e(LOGTAG, "Failed to get the plugged status!");
- } else {
- // Likely, if plugged > 0, it's likely plugged and charging but the doc
- // isn't clear about that.
- sCharging = plugged != 0;
- }
-
- if (sCharging != previousCharging) {
- sRemainingTime = kUnknownRemainingTime;
- // The new remaining time is going to take some time to show up but
- // it's the best way to show a not too wrong value.
- sLastLevelChange = 0;
- }
-
- // We need two doubles because sLevel is a double.
- double current = (double)intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
- double max = (double)intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
- if (current == -1 || max == -1) {
- Log.e(LOGTAG, "Failed to get battery level!");
- sLevel = kDefaultLevel;
- } else {
- sLevel = current / max;
- }
-
- if (sLevel == 1.0 && sCharging) {
- sRemainingTime = kDefaultRemainingTime;
- } else if (sLevel != previousLevel) {
- // Estimate remaining time.
- if (sLastLevelChange != 0) {
- // Use elapsedRealtime() because we want to track time across device sleeps.
- long currentTime = SystemClock.elapsedRealtime();
- long dt = (currentTime - sLastLevelChange) / 1000;
- double dLevel = sLevel - previousLevel;
-
- if (sCharging) {
- if (dLevel < 0) {
- Log.w(LOGTAG, "When charging, level should increase!");
- sRemainingTime = kUnknownRemainingTime;
- } else {
- sRemainingTime = Math.round(dt / dLevel * (1.0 - sLevel));
- }
- } else {
- if (dLevel > 0) {
- Log.w(LOGTAG, "When discharging, level should decrease!");
- sRemainingTime = kUnknownRemainingTime;
- } else {
- sRemainingTime = Math.round(dt / -dLevel * sLevel);
- }
- }
-
- sLastLevelChange = currentTime;
- } else {
- // That's the first time we got an update, we can't do anything.
- sLastLevelChange = SystemClock.elapsedRealtime();
- }
- }
- } else {
- sLevel = kDefaultLevel;
- sCharging = kDefaultCharging;
- sRemainingTime = kDefaultRemainingTime;
- }
-
- /*
- * We want to inform listeners if the following conditions are fulfilled:
- * - we have at least one observer;
- * - the charging state or the level has changed.
- *
- * Note: no need to check for a remaining time change given that it's only
- * updated if there is a level change or a charging change.
- *
- * The idea is to prevent doing all the way to the DOM code in the child
- * process to finally not send an event.
- */
- if (sNotificationsEnabled &&
- (previousCharging != isCharging() || previousLevel != getLevel())) {
- GeckoAppShell.notifyBatteryChange(getLevel(), isCharging(), getRemainingTime());
- }
- }
-
- public static boolean isCharging() {
- return sCharging;
- }
-
- public static double getLevel() {
- return sLevel;
- }
-
- public static double getRemainingTime() {
- return sRemainingTime;
- }
-
- public static void enableNotifications() {
- sNotificationsEnabled = true;
- }
-
- public static void disableNotifications() {
- sNotificationsEnabled = false;
- }
-
- public static double[] getCurrentInformation() {
- return new double[] { getLevel(), isCharging() ? 1.0 : 0.0, getRemainingTime() };
- }
-}
diff --git a/mobile/android/base/GeckoConnectivityReceiver.java b/mobile/android/base/GeckoConnectivityReceiver.java
deleted file mode 100644
index 8c9d1b19c..000000000
--- a/mobile/android/base/GeckoConnectivityReceiver.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; 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.gecko;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.util.Log;
-
-public class GeckoConnectivityReceiver extends BroadcastReceiver {
- /*
- * Keep the below constants in sync with
- * http://mxr.mozilla.org/mozilla-central/source/netwerk/base/public/nsINetworkLinkService.idl
- */
- private static final String LINK_DATA_UP = "up";
- private static final String LINK_DATA_DOWN = "down";
- private static final String LINK_DATA_UNKNOWN = "unknown";
-
- private static final String LOGTAG = "GeckoConnectivityReceiver";
-
- private static GeckoConnectivityReceiver sInstance = new GeckoConnectivityReceiver();
-
- private IntentFilter mFilter;
- private Context mApplicationContext;
- private boolean mIsEnabled;
-
- public static GeckoConnectivityReceiver getInstance() {
- return sInstance;
- }
-
- private GeckoConnectivityReceiver() {
- mFilter = new IntentFilter();
- mFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
- }
-
- public void init(Context context) {
- mApplicationContext = context.getApplicationContext();
- }
-
- public synchronized void start() {
- if (!mIsEnabled) {
- // registerReceiver will return null if registering fails
- if (mApplicationContext.registerReceiver(this, mFilter) == null) {
- Log.e(LOGTAG, "Registering receiver failed");
- } else {
- mIsEnabled = true;
- }
- }
- }
-
- public synchronized void stop() {
- if (mIsEnabled) {
- mApplicationContext.unregisterReceiver(this);
- mIsEnabled = false;
- }
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
- NetworkInfo info = cm.getActiveNetworkInfo();
-
- String status;
- if (info == null) {
- status = LINK_DATA_UNKNOWN;
- } else if (!info.isConnected()) {
- status = LINK_DATA_DOWN;
- } else {
- status = LINK_DATA_UP;
- }
-
- if (GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoRunning)) {
- GeckoAppShell.sendEventToGecko(GeckoEvent.createNetworkLinkChangeEvent(status));
- }
- }
-}
diff --git a/mobile/android/base/GeckoEditable.java b/mobile/android/base/GeckoEditable.java
deleted file mode 100644
index 887b6bb81..000000000
--- a/mobile/android/base/GeckoEditable.java
+++ /dev/null
@@ -1,1207 +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.gecko;
-
-import org.mozilla.gecko.gfx.InputConnectionHandler;
-import org.mozilla.gecko.gfx.LayerView;
-import org.mozilla.gecko.util.ThreadUtils;
-
-import android.os.Build;
-import android.os.Handler;
-import android.os.Looper;
-import android.text.Editable;
-import android.text.InputFilter;
-import android.text.Selection;
-import android.text.Spannable;
-import android.text.SpannableString;
-import android.text.SpannableStringBuilder;
-import android.text.Spanned;
-import android.text.TextPaint;
-import android.text.TextUtils;
-import android.text.style.CharacterStyle;
-import android.util.Log;
-import android.view.KeyCharacterMap;
-import android.view.KeyEvent;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.Semaphore;
-
-// interface for the IC thread
-interface GeckoEditableClient {
- void sendEvent(GeckoEvent event);
- Editable getEditable();
- void setUpdateGecko(boolean update);
- void setSuppressKeyUp(boolean suppress);
- Handler getInputConnectionHandler();
- boolean setInputConnectionHandler(Handler handler);
-}
-
-/* interface for the Editable to listen to the Gecko thread
- and also for the IC thread to listen to the Editable */
-interface GeckoEditableListener {
- // IME notification type for notifyIME(), corresponding to NotificationToIME enum in Gecko
- final int NOTIFY_IME_REPLY_EVENT = -1;
- final int NOTIFY_IME_OF_FOCUS = 1;
- final int NOTIFY_IME_OF_BLUR = 2;
- final int NOTIFY_IME_TO_COMMIT_COMPOSITION = 4;
- final int NOTIFY_IME_TO_CANCEL_COMPOSITION = 5;
- // IME enabled state for notifyIMEContext()
- final int IME_STATE_DISABLED = 0;
- final int IME_STATE_ENABLED = 1;
- final int IME_STATE_PASSWORD = 2;
- final int IME_STATE_PLUGIN = 3;
-
- void notifyIME(int type);
- void notifyIMEContext(int state, String typeHint,
- String modeHint, String actionHint);
- void onSelectionChange(int start, int end);
- void onTextChange(String text, int start, int oldEnd, int newEnd);
-}
-
-/*
- GeckoEditable implements only some functions of Editable
- The field mText contains the actual underlying
- SpannableStringBuilder/Editable that contains our text.
-*/
-final class GeckoEditable
- implements InvocationHandler, Editable,
- GeckoEditableClient, GeckoEditableListener {
-
- private static final boolean DEBUG = false;
- private static final String LOGTAG = "GeckoEditable";
-
- // Filters to implement Editable's filtering functionality
- private InputFilter[] mFilters;
-
- private final SpannableStringBuilder mText;
- private final SpannableStringBuilder mChangedText;
- private final Editable mProxy;
- private final ActionQueue mActionQueue;
-
- // mIcRunHandler is the Handler that currently runs Gecko-to-IC Runnables
- // mIcPostHandler is the Handler to post Gecko-to-IC Runnables to
- // The two can be different when switching from one handler to another
- private Handler mIcRunHandler;
- private Handler mIcPostHandler;
-
- private GeckoEditableListener mListener;
- private int mSavedSelectionStart;
- private volatile int mGeckoUpdateSeqno;
- private int mIcUpdateSeqno;
- private int mLastIcUpdateSeqno;
- private boolean mUpdateGecko;
- private boolean mFocused;
- private volatile boolean mSuppressKeyUp;
-
- /* An action that alters the Editable
-
- Each action corresponds to a Gecko event. While the Gecko event is being sent to the Gecko
- thread, the action stays on top of mActions queue. After the Gecko event is processed and
- replied, the action is removed from the queue
- */
- private static final class Action {
- // For input events (keypress, etc.); use with IME_SYNCHRONIZE
- static final int TYPE_EVENT = 0;
- // For Editable.replace() call; use with IME_REPLACE_TEXT
- static final int TYPE_REPLACE_TEXT = 1;
- /* For Editable.setSpan(Selection...) call; use with IME_SYNCHRONIZE
- Note that we don't use this with IME_SET_SELECTION because we don't want to update the
- Gecko selection at the point of this action. The Gecko selection is updated only after
- IC has updated its selection (during IME_SYNCHRONIZE reply) */
- static final int TYPE_SET_SELECTION = 2;
- // For Editable.setSpan() call; use with IME_SYNCHRONIZE
- static final int TYPE_SET_SPAN = 3;
- // For Editable.removeSpan() call; use with IME_SYNCHRONIZE
- static final int TYPE_REMOVE_SPAN = 4;
- // For focus events (in notifyIME); use with IME_ACKNOWLEDGE_FOCUS
- static final int TYPE_ACKNOWLEDGE_FOCUS = 5;
- // For switching handler; use with IME_SYNCHRONIZE
- static final int TYPE_SET_HANDLER = 6;
-
- final int mType;
- int mStart;
- int mEnd;
- CharSequence mSequence;
- Object mSpanObject;
- int mSpanFlags;
- boolean mShouldUpdate;
- Handler mHandler;
-
- Action(int type) {
- mType = type;
- }
-
- static Action newReplaceText(CharSequence text, int start, int end) {
- if (start < 0 || start > end) {
- throw new IllegalArgumentException(
- "invalid replace text offsets: " + start + " to " + end);
- }
- final Action action = new Action(TYPE_REPLACE_TEXT);
- action.mSequence = text;
- action.mStart = start;
- action.mEnd = end;
- return action;
- }
-
- static Action newSetSelection(int start, int end) {
- // start == -1 when the start offset should remain the same
- // end == -1 when the end offset should remain the same
- if (start < -1 || end < -1) {
- throw new IllegalArgumentException(
- "invalid selection offsets: " + start + " to " + end);
- }
- final Action action = new Action(TYPE_SET_SELECTION);
- action.mStart = start;
- action.mEnd = end;
- return action;
- }
-
- static Action newSetSpan(Object object, int start, int end, int flags) {
- if (start < 0 || start > end) {
- throw new IllegalArgumentException(
- "invalid span offsets: " + start + " to " + end);
- }
- final Action action = new Action(TYPE_SET_SPAN);
- action.mSpanObject = object;
- action.mStart = start;
- action.mEnd = end;
- action.mSpanFlags = flags;
- return action;
- }
-
- static Action newSetHandler(Handler handler) {
- final Action action = new Action(TYPE_SET_HANDLER);
- action.mHandler = handler;
- return action;
- }
- }
-
- /* Queue of editing actions sent to Gecko thread that
- the Gecko thread has not responded to yet */
- private final class ActionQueue {
- private final ConcurrentLinkedQueue<Action> mActions;
- private final Semaphore mActionsActive;
- private KeyCharacterMap mKeyMap;
-
- ActionQueue() {
- mActions = new ConcurrentLinkedQueue<Action>();
- mActionsActive = new Semaphore(1);
- }
-
- void offer(Action action) {
- if (DEBUG) {
- assertOnIcThread();
- Log.d(LOGTAG, "offer: Action(" +
- getConstantName(Action.class, "TYPE_", action.mType) + ")");
- }
- /* Events don't need update because they generate text/selection
- notifications which will do the updating for us */
- if (action.mType != Action.TYPE_EVENT &&
- action.mType != Action.TYPE_ACKNOWLEDGE_FOCUS &&
- action.mType != Action.TYPE_SET_HANDLER) {
- action.mShouldUpdate = mUpdateGecko;
- }
- if (mActions.isEmpty()) {
- mActionsActive.acquireUninterruptibly();
- mActions.offer(action);
- } else synchronized(this) {
- // tryAcquire here in case Gecko thread has just released it
- mActionsActive.tryAcquire();
- mActions.offer(action);
- }
- switch (action.mType) {
- case Action.TYPE_EVENT:
- case Action.TYPE_SET_SELECTION:
- case Action.TYPE_SET_SPAN:
- case Action.TYPE_REMOVE_SPAN:
- case Action.TYPE_SET_HANDLER:
- GeckoAppShell.sendEventToGecko(GeckoEvent.createIMEEvent(
- GeckoEvent.ImeAction.IME_SYNCHRONIZE));
- break;
- case Action.TYPE_REPLACE_TEXT:
- // try key events first
- sendCharKeyEvents(action);
- GeckoAppShell.sendEventToGecko(GeckoEvent.createIMEReplaceEvent(
- action.mStart, action.mEnd, action.mSequence.toString()));
- break;
- case Action.TYPE_ACKNOWLEDGE_FOCUS:
- GeckoAppShell.sendEventToGecko(GeckoEvent.createIMEEvent(
- GeckoEvent.ImeAction.IME_ACKNOWLEDGE_FOCUS));
- break;
- }
- ++mIcUpdateSeqno;
- }
-
- private KeyEvent [] synthesizeKeyEvents(CharSequence cs) {
- try {
- if (mKeyMap == null) {
- mKeyMap = KeyCharacterMap.load(
- Build.VERSION.SDK_INT < 11 ? KeyCharacterMap.ALPHA :
- KeyCharacterMap.VIRTUAL_KEYBOARD);
- }
- } catch (Exception e) {
- // KeyCharacterMap.UnavailableExcepton is not found on Gingerbread;
- // besides, it seems like HC and ICS will throw something other than
- // KeyCharacterMap.UnavailableExcepton; so use a generic Exception here
- return null;
- }
- KeyEvent [] keyEvents = mKeyMap.getEvents(cs.toString().toCharArray());
- if (keyEvents == null || keyEvents.length == 0) {
- return null;
- }
- return keyEvents;
- }
-
- private void sendCharKeyEvents(Action action) {
- if (action.mSequence.length() == 0 ||
- (action.mSequence instanceof Spannable &&
- ((Spannable)action.mSequence).nextSpanTransition(
- -1, Integer.MAX_VALUE, null) < Integer.MAX_VALUE)) {
- // Spans are not preserved when we use key events,
- // so we need the sequence to not have any spans
- return;
- }
- KeyEvent [] keyEvents = synthesizeKeyEvents(action.mSequence);
- if (keyEvents == null) {
- return;
- }
- for (KeyEvent event : keyEvents) {
- if (KeyEvent.isModifierKey(event.getKeyCode())) {
- continue;
- }
- if (event.getAction() == KeyEvent.ACTION_UP && mSuppressKeyUp) {
- continue;
- }
- if (DEBUG) {
- Log.d(LOGTAG, "sending: " + event);
- }
- GeckoAppShell.sendEventToGecko(GeckoEvent.createIMEKeyEvent(event));
- }
- }
-
- void poll() {
- if (DEBUG) {
- ThreadUtils.assertOnGeckoThread();
- }
- if (mActions.isEmpty()) {
- throw new IllegalStateException("empty actions queue");
- }
- mActions.poll();
- // Don't bother locking if queue is not empty yet
- if (mActions.isEmpty()) {
- synchronized(this) {
- if (mActions.isEmpty()) {
- mActionsActive.release();
- }
- }
- }
- }
-
- Action peek() {
- if (DEBUG) {
- ThreadUtils.assertOnGeckoThread();
- }
- if (mActions.isEmpty()) {
- throw new IllegalStateException("empty actions queue");
- }
- return mActions.peek();
- }
-
- void syncWithGecko() {
- if (DEBUG) {
- assertOnIcThread();
- }
- if (mFocused && !mActions.isEmpty()) {
- if (DEBUG) {
- Log.d(LOGTAG, "syncWithGecko blocking on thread " +
- Thread.currentThread().getName());
- }
- mActionsActive.acquireUninterruptibly();
- mActionsActive.release();
- } else if (DEBUG && !mFocused) {
- Log.d(LOGTAG, "skipped syncWithGecko (no focus)");
- }
- }
-
- boolean isEmpty() {
- return mActions.isEmpty();
- }
- }
-
- GeckoEditable() {
- mActionQueue = new ActionQueue();
- mSavedSelectionStart = -1;
- mUpdateGecko = true;
-
- mText = new SpannableStringBuilder();
- mChangedText = new SpannableStringBuilder();
-
- final Class<?>[] PROXY_INTERFACES = { Editable.class };
- mProxy = (Editable)Proxy.newProxyInstance(
- Editable.class.getClassLoader(),
- PROXY_INTERFACES, this);
-
- LayerView v = GeckoAppShell.getLayerView();
- mListener = GeckoInputConnection.create(v, this);
-
- mIcRunHandler = mIcPostHandler = ThreadUtils.getUiHandler();
- }
-
- private boolean onIcThread() {
- return mIcRunHandler.getLooper() == Looper.myLooper();
- }
-
- private void assertOnIcThread() {
- ThreadUtils.assertOnThread(mIcRunHandler.getLooper().getThread());
- }
-
- private void geckoPostToIc(Runnable runnable) {
- mIcPostHandler.post(runnable);
- }
-
- private void geckoUpdateGecko(final boolean force) {
- /* We do not increment the seqno here, but only check it, because geckoUpdateGecko is a
- request for update. If we incremented the seqno here, geckoUpdateGecko would have
- prevented other updates from occurring */
- final int seqnoWhenPosted = mGeckoUpdateSeqno;
-
- geckoPostToIc(new Runnable() {
- @Override
- public void run() {
- mActionQueue.syncWithGecko();
- if (seqnoWhenPosted == mGeckoUpdateSeqno) {
- icUpdateGecko(force);
- }
- }
- });
- }
-
- private Object getField(Object obj, String field, Object def) {
- try {
- return obj.getClass().getField(field).get(obj);
- } catch (Exception e) {
- return def;
- }
- }
-
- private void icUpdateGecko(boolean force) {
-
- if (!force && mIcUpdateSeqno == mLastIcUpdateSeqno) {
- if (DEBUG) {
- Log.d(LOGTAG, "icUpdateGecko() skipped");
- }
- return;
- }
- mLastIcUpdateSeqno = mIcUpdateSeqno;
- mActionQueue.syncWithGecko();
-
- if (DEBUG) {
- Log.d(LOGTAG, "icUpdateGecko()");
- }
-
- final int selStart = mText.getSpanStart(Selection.SELECTION_START);
- final int selEnd = mText.getSpanEnd(Selection.SELECTION_END);
- int composingStart = mText.length();
- int composingEnd = 0;
- Object[] spans = mText.getSpans(0, composingStart, Object.class);
-
- for (Object span : spans) {
- if ((mText.getSpanFlags(span) & Spanned.SPAN_COMPOSING) != 0) {
- composingStart = Math.min(composingStart, mText.getSpanStart(span));
- composingEnd = Math.max(composingEnd, mText.getSpanEnd(span));
- }
- }
- if (DEBUG) {
- Log.d(LOGTAG, " range = " + composingStart + "-" + composingEnd);
- Log.d(LOGTAG, " selection = " + selStart + "-" + selEnd);
- }
- if (composingStart >= composingEnd) {
- if (selStart >= 0 && selEnd >= 0) {
- GeckoAppShell.sendEventToGecko(
- GeckoEvent.createIMESelectEvent(selStart, selEnd));
- } else {
- GeckoAppShell.sendEventToGecko(GeckoEvent.createIMEEvent(
- GeckoEvent.ImeAction.IME_REMOVE_COMPOSITION));
- }
- return;
- }
-
- if (selEnd >= composingStart && selEnd <= composingEnd) {
- GeckoAppShell.sendEventToGecko(GeckoEvent.createIMERangeEvent(
- selEnd - composingStart, selEnd - composingStart,
- GeckoEvent.IME_RANGE_CARETPOSITION, 0, 0, false, 0, 0, 0));
- }
- int rangeStart = composingStart;
- TextPaint tp = new TextPaint();
- TextPaint emptyTp = new TextPaint();
- // set initial foreground color to 0, because we check for tp.getColor() == 0
- // below to decide whether to pass a foreground color to Gecko
- emptyTp.setColor(0);
- do {
- int rangeType, rangeStyles = 0, rangeLineStyle = GeckoEvent.IME_RANGE_LINE_NONE;
- boolean rangeBoldLine = false;
- int rangeForeColor = 0, rangeBackColor = 0, rangeLineColor = 0;
- int rangeEnd = mText.nextSpanTransition(rangeStart, composingEnd, Object.class);
-
- if (selStart > rangeStart && selStart < rangeEnd) {
- rangeEnd = selStart;
- } else if (selEnd > rangeStart && selEnd < rangeEnd) {
- rangeEnd = selEnd;
- }
- CharacterStyle[] styleSpans =
- mText.getSpans(rangeStart, rangeEnd, CharacterStyle.class);
-
- if (DEBUG) {
- Log.d(LOGTAG, " found " + styleSpans.length + " spans @ " +
- rangeStart + "-" + rangeEnd);
- }
-
- if (styleSpans.length == 0) {
- rangeType = (selStart == rangeStart && selEnd == rangeEnd)
- ? GeckoEvent.IME_RANGE_SELECTEDRAWTEXT
- : GeckoEvent.IME_RANGE_RAWINPUT;
- } else {
- rangeType = (selStart == rangeStart && selEnd == rangeEnd)
- ? GeckoEvent.IME_RANGE_SELECTEDCONVERTEDTEXT
- : GeckoEvent.IME_RANGE_CONVERTEDTEXT;
- tp.set(emptyTp);
- for (CharacterStyle span : styleSpans) {
- span.updateDrawState(tp);
- }
- int tpUnderlineColor = 0;
- float tpUnderlineThickness = 0.0f;
- // These TextPaint fields only exist on Android ICS+ and are not in the SDK
- if (Build.VERSION.SDK_INT >= 14) {
- tpUnderlineColor = (Integer)getField(tp, "underlineColor", 0);
- tpUnderlineThickness = (Float)getField(tp, "underlineThickness", 0.0f);
- }
- if (tpUnderlineColor != 0) {
- rangeStyles |= GeckoEvent.IME_RANGE_UNDERLINE | GeckoEvent.IME_RANGE_LINECOLOR;
- rangeLineColor = tpUnderlineColor;
- // Approximately translate underline thickness to what Gecko understands
- if (tpUnderlineThickness <= 0.5f) {
- rangeLineStyle = GeckoEvent.IME_RANGE_LINE_DOTTED;
- } else {
- rangeLineStyle = GeckoEvent.IME_RANGE_LINE_SOLID;
- if (tpUnderlineThickness >= 2.0f) {
- rangeBoldLine = true;
- }
- }
- } else if (tp.isUnderlineText()) {
- rangeStyles |= GeckoEvent.IME_RANGE_UNDERLINE;
- rangeLineStyle = GeckoEvent.IME_RANGE_LINE_SOLID;
- }
- if (tp.getColor() != 0) {
- rangeStyles |= GeckoEvent.IME_RANGE_FORECOLOR;
- rangeForeColor = tp.getColor();
- }
- if (tp.bgColor != 0) {
- rangeStyles |= GeckoEvent.IME_RANGE_BACKCOLOR;
- rangeBackColor = tp.bgColor;
- }
- }
- GeckoAppShell.sendEventToGecko(GeckoEvent.createIMERangeEvent(
- rangeStart - composingStart, rangeEnd - composingStart,
- rangeType, rangeStyles, rangeLineStyle, rangeBoldLine,
- rangeForeColor, rangeBackColor, rangeLineColor));
- rangeStart = rangeEnd;
-
- if (DEBUG) {
- Log.d(LOGTAG, " added " + rangeType +
- " : " + Integer.toHexString(rangeStyles) +
- " : " + Integer.toHexString(rangeForeColor) +
- " : " + Integer.toHexString(rangeBackColor));
- }
- } while (rangeStart < composingEnd);
-
- GeckoAppShell.sendEventToGecko(GeckoEvent.createIMECompositionEvent(
- composingStart, composingEnd));
- }
-
- // GeckoEditableClient interface
-
- @Override
- public void sendEvent(final GeckoEvent event) {
- if (DEBUG) {
- Log.d(LOGTAG, "sendEvent(" + event + ")");
- }
- if (!onIcThread()) {
- // Events may get dispatched to the main thread;
- // reroute to our IC thread instead
- mIcRunHandler.post(new Runnable() {
- @Override
- public void run() {
- sendEvent(event);
- }
- });
- return;
- }
- /*
- We are actually sending two events to Gecko here,
- 1. Event from the event parameter (key event, etc.)
- 2. Sync event from the mActionQueue.offer call
- The first event is a normal GeckoEvent that does not reply back to us,
- the second sync event will have a reply, during which we see that there is a pending
- event-type action, and update the selection/composition/etc. accordingly.
- */
- GeckoAppShell.sendEventToGecko(event);
- mActionQueue.offer(new Action(Action.TYPE_EVENT));
- }
-
- @Override
- public Editable getEditable() {
- if (!onIcThread()) {
- // Android may be holding an old InputConnection; ignore
- if (DEBUG) {
- Log.i(LOGTAG, "getEditable() called on non-IC thread");
- }
- return null;
- }
- return mProxy;
- }
-
- @Override
- public void setUpdateGecko(boolean update) {
- if (!onIcThread()) {
- // Android may be holding an old InputConnection; ignore
- if (DEBUG) {
- Log.i(LOGTAG, "setUpdateGecko() called on non-IC thread");
- }
- return;
- }
- if (update) {
- icUpdateGecko(false);
- }
- mUpdateGecko = update;
- }
-
- @Override
- public void setSuppressKeyUp(boolean suppress) {
- if (DEBUG) {
- // only used by key event handler
- ThreadUtils.assertOnUiThread();
- }
- // Suppress key up event generated as a result of
- // translating characters to key events
- mSuppressKeyUp = suppress;
- }
-
- @Override
- public Handler getInputConnectionHandler() {
- // Can be called from either UI thread or IC thread;
- // care must be taken to avoid race conditions
- return mIcRunHandler;
- }
-
- @Override
- public boolean setInputConnectionHandler(Handler handler) {
- if (handler == mIcPostHandler) {
- return true;
- }
- if (!mFocused) {
- return false;
- }
- if (DEBUG) {
- assertOnIcThread();
- }
- // There are three threads at this point: Gecko thread, old IC thread, and new IC
- // thread, and we want to safely switch from old IC thread to new IC thread.
- // We first send a TYPE_SET_HANDLER action to the Gecko thread; this ensures that
- // the Gecko thread is stopped at a known point. At the same time, the old IC
- // thread blocks on the action; this ensures that the old IC thread is stopped at
- // a known point. Finally, inside the Gecko thread, we post a Runnable to the old
- // IC thread; this Runnable switches from old IC thread to new IC thread. We
- // switch IC thread on the old IC thread to ensure any pending Runnables on the
- // old IC thread are processed before we switch over. Inside the Gecko thread, we
- // also post a Runnable to the new IC thread; this Runnable blocks until the
- // switch is complete; this ensures that the new IC thread won't accept
- // InputConnection calls until after the switch.
- mActionQueue.offer(Action.newSetHandler(handler));
- mActionQueue.syncWithGecko();
- return true;
- }
-
- private void geckoSetIcHandler(final Handler newHandler) {
- geckoPostToIc(new Runnable() { // posting to old IC thread
- @Override
- public void run() {
- synchronized (newHandler) {
- mIcRunHandler = newHandler;
- newHandler.notify();
- }
- }
- });
-
- // At this point, all future Runnables should be posted to the new IC thread, but
- // we don't switch mIcRunHandler yet because there may be pending Runnables on the
- // old IC thread still waiting to run.
- mIcPostHandler = newHandler;
-
- geckoPostToIc(new Runnable() { // posting to new IC thread
- @Override
- public void run() {
- synchronized (newHandler) {
- while (mIcRunHandler != newHandler) {
- try {
- newHandler.wait();
- } catch (InterruptedException e) {
- }
- }
- }
- }
- });
- }
-
- // GeckoEditableListener interface
-
- private void geckoActionReply() {
- if (DEBUG) {
- // GeckoEditableListener methods should all be called from the Gecko thread
- ThreadUtils.assertOnGeckoThread();
- }
- final Action action = mActionQueue.peek();
-
- if (DEBUG) {
- Log.d(LOGTAG, "reply: Action(" +
- getConstantName(Action.class, "TYPE_", action.mType) + ")");
- }
- switch (action.mType) {
- case Action.TYPE_SET_SELECTION:
- final int len = mText.length();
- final int curStart = Selection.getSelectionStart(mText);
- final int curEnd = Selection.getSelectionEnd(mText);
- // start == -1 when the start offset should remain the same
- // end == -1 when the end offset should remain the same
- final int selStart = Math.min(action.mStart < 0 ? curStart : action.mStart, len);
- final int selEnd = Math.min(action.mEnd < 0 ? curEnd : action.mEnd, len);
-
- if (selStart < action.mStart || selEnd < action.mEnd) {
- Log.w(LOGTAG, "IME sync error: selection out of bounds");
- }
- Selection.setSelection(mText, selStart, selEnd);
- geckoPostToIc(new Runnable() {
- @Override
- public void run() {
- mActionQueue.syncWithGecko();
- final int start = Selection.getSelectionStart(mText);
- final int end = Selection.getSelectionEnd(mText);
- if (selStart == start && selEnd == end) {
- // There has not been another new selection in the mean time that
- // made this notification out-of-date
- mListener.onSelectionChange(start, end);
- }
- }
- });
- break;
- case Action.TYPE_SET_SPAN:
- mText.setSpan(action.mSpanObject, action.mStart, action.mEnd, action.mSpanFlags);
- break;
- case Action.TYPE_SET_HANDLER:
- geckoSetIcHandler(action.mHandler);
- break;
- }
- if (action.mShouldUpdate) {
- geckoUpdateGecko(false);
- }
- }
-
- @Override
- public void notifyIME(final int type) {
- if (DEBUG) {
- // GeckoEditableListener methods should all be called from the Gecko thread
- ThreadUtils.assertOnGeckoThread();
- // NOTIFY_IME_REPLY_EVENT is logged separately, inside geckoActionReply()
- if (type != NOTIFY_IME_REPLY_EVENT) {
- Log.d(LOGTAG, "notifyIME(" +
- getConstantName(GeckoEditableListener.class, "NOTIFY_IME_", type) +
- ")");
- }
- }
- if (type == NOTIFY_IME_REPLY_EVENT) {
- try {
- if (mFocused) {
- // When mFocused is false, the reply is for a stale action,
- // and we should not do anything
- geckoActionReply();
- } else if (DEBUG) {
- Log.d(LOGTAG, "discarding stale reply");
- }
- } finally {
- // Ensure action is always removed from queue
- // even if stale action results in exception in geckoActionReply
- mActionQueue.poll();
- }
- return;
- }
- geckoPostToIc(new Runnable() {
- @Override
- public void run() {
- if (type == NOTIFY_IME_OF_BLUR) {
- mFocused = false;
- } else if (type == NOTIFY_IME_OF_FOCUS) {
- mFocused = true;
- // Unmask events on the Gecko side
- mActionQueue.offer(new Action(Action.TYPE_ACKNOWLEDGE_FOCUS));
- }
- // Make sure there are no other things going on. If we sent
- // GeckoEvent.IME_ACKNOWLEDGE_FOCUS, this line also makes us
- // wait for Gecko to update us on the newly focused content
- mActionQueue.syncWithGecko();
- mListener.notifyIME(type);
- }
- });
- }
-
- @Override
- public void notifyIMEContext(final int state, final String typeHint,
- final String modeHint, final String actionHint) {
- // Because we want to be able to bind GeckoEditable to the newest LayerView instance,
- // this can be called from the Java IC thread in addition to the Gecko thread.
- if (DEBUG) {
- Log.d(LOGTAG, "notifyIMEContext(" +
- getConstantName(GeckoEditableListener.class, "IME_STATE_", state) +
- ", \"" + typeHint + "\", \"" + modeHint + "\", \"" + actionHint + "\")");
- }
- geckoPostToIc(new Runnable() {
- @Override
- public void run() {
- // Make sure there are no other things going on
- mActionQueue.syncWithGecko();
- // Set InputConnectionHandler in notifyIMEContext because
- // GeckoInputConnection.notifyIMEContext calls restartInput() which will invoke
- // InputConnectionHandler.onCreateInputConnection
- LayerView v = GeckoAppShell.getLayerView();
- if (v != null) {
- mListener = GeckoInputConnection.create(v, GeckoEditable.this);
- v.setInputConnectionHandler((InputConnectionHandler)mListener);
- mListener.notifyIMEContext(state, typeHint, modeHint, actionHint);
- }
- }
- });
- }
-
- @Override
- public void onSelectionChange(final int start, final int end) {
- if (DEBUG) {
- // GeckoEditableListener methods should all be called from the Gecko thread
- ThreadUtils.assertOnGeckoThread();
- Log.d(LOGTAG, "onSelectionChange(" + start + ", " + end + ")");
- }
- if (start < 0 || start > mText.length() || end < 0 || end > mText.length()) {
- throw new IllegalArgumentException("invalid selection notification range: " +
- start + " to " + end + ", length: " + mText.length());
- }
- final int seqnoWhenPosted = ++mGeckoUpdateSeqno;
-
- /* An event (keypress, etc.) has potentially changed the selection,
- synchronize the selection here. There is not a race with the IC thread
- because the IC thread should be blocked on the event action */
- if (!mActionQueue.isEmpty() &&
- mActionQueue.peek().mType == Action.TYPE_EVENT) {
- Selection.setSelection(mText, start, end);
- return;
- }
-
- geckoPostToIc(new Runnable() {
- @Override
- public void run() {
- mActionQueue.syncWithGecko();
- /* check to see there has not been another action that potentially changed the
- selection. If so, we can skip this update because we know there is another
- update right after this one that will replace the effect of this update */
- if (mGeckoUpdateSeqno == seqnoWhenPosted) {
- /* In this case, Gecko's selection has changed and it's notifying us to change
- Java's selection. In the normal case, whenever Java's selection changes,
- we go back and set Gecko's selection as well. However, in this case,
- since Gecko's selection is already up-to-date, we skip this step. */
- boolean oldUpdateGecko = mUpdateGecko;
- mUpdateGecko = false;
- Selection.setSelection(mProxy, start, end);
- mUpdateGecko = oldUpdateGecko;
- }
- }
- });
- }
-
- private void geckoReplaceText(int start, int oldEnd, CharSequence newText) {
- // Don't use replace() because Gingerbread has a bug where if the replaced text
- // has the same spans as the original text, the spans will end up being deleted
- mText.delete(start, oldEnd);
- mText.insert(start, newText);
- }
-
- @Override
- public void onTextChange(final String text, final int start,
- final int unboundedOldEnd, final int unboundedNewEnd) {
- if (DEBUG) {
- // GeckoEditableListener methods should all be called from the Gecko thread
- ThreadUtils.assertOnGeckoThread();
- Log.d(LOGTAG, "onTextChange(\"" + text + "\", " + start + ", " +
- unboundedOldEnd + ", " + unboundedNewEnd + ")");
- }
- if (start < 0 || start > unboundedOldEnd) {
- throw new IllegalArgumentException("invalid text notification range: " +
- start + " to " + unboundedOldEnd);
- }
- /* For the "end" parameters, Gecko can pass in a large
- number to denote "end of the text". Fix that here */
- final int oldEnd = unboundedOldEnd > mText.length() ? mText.length() : unboundedOldEnd;
- // new end should always match text
- if (start != 0 && unboundedNewEnd != (start + text.length())) {
- throw new IllegalArgumentException("newEnd does not match text: " +
- unboundedNewEnd + " vs " + (start + text.length()));
- }
- final int newEnd = start + text.length();
-
- /* Text changes affect the selection as well, and we may not receive another selection
- update as a result of selection notification masking on the Gecko side; therefore,
- in order to prevent previous stale selection notifications from occurring, we need
- to increment the seqno here as well */
- ++mGeckoUpdateSeqno;
-
- mChangedText.clearSpans();
- mChangedText.replace(0, mChangedText.length(), text);
- // Preserve as many spans as possible
- TextUtils.copySpansFrom(mText, start, Math.min(oldEnd, newEnd),
- Object.class, mChangedText, 0);
-
- if (!mActionQueue.isEmpty()) {
- final Action action = mActionQueue.peek();
- if (action.mType == Action.TYPE_REPLACE_TEXT &&
- start <= action.mStart &&
- action.mStart + action.mSequence.length() <= newEnd) {
-
- // actionNewEnd is the new end of the original replacement action
- final int actionNewEnd = action.mStart + action.mSequence.length();
- int selStart = Selection.getSelectionStart(mText);
- int selEnd = Selection.getSelectionEnd(mText);
-
- // Replace old spans with new spans
- mChangedText.replace(action.mStart - start, actionNewEnd - start,
- action.mSequence);
- geckoReplaceText(start, oldEnd, mChangedText);
-
- // delete/insert above might have moved our selection to somewhere else
- // this happens when the Gecko text change covers a larger range than
- // the original replacement action. Fix selection here
- if (selStart >= start && selStart <= oldEnd) {
- selStart = selStart < action.mStart ? selStart :
- selStart < action.mEnd ? actionNewEnd :
- selStart + actionNewEnd - action.mEnd;
- mText.setSpan(Selection.SELECTION_START, selStart, selStart,
- Spanned.SPAN_POINT_POINT);
- }
- if (selEnd >= start && selEnd <= oldEnd) {
- selEnd = selEnd < action.mStart ? selEnd :
- selEnd < action.mEnd ? actionNewEnd :
- selEnd + actionNewEnd - action.mEnd;
- mText.setSpan(Selection.SELECTION_END, selEnd, selEnd,
- Spanned.SPAN_POINT_POINT);
- }
- } else {
- geckoReplaceText(start, oldEnd, mChangedText);
- }
- } else {
- geckoReplaceText(start, oldEnd, mChangedText);
- }
- geckoPostToIc(new Runnable() {
- @Override
- public void run() {
- mListener.onTextChange(text, start, oldEnd, newEnd);
- }
- });
- }
-
- // InvocationHandler interface
-
- static String getConstantName(Class<?> cls, String prefix, Object value) {
- for (Field fld : cls.getDeclaredFields()) {
- try {
- if (fld.getName().startsWith(prefix) &&
- fld.get(null).equals(value)) {
- return fld.getName();
- }
- } catch (IllegalAccessException e) {
- }
- }
- return String.valueOf(value);
- }
-
- static StringBuilder debugAppend(StringBuilder sb, Object obj) {
- if (obj == null) {
- sb.append("null");
- } else if (obj instanceof GeckoEditable) {
- sb.append("GeckoEditable");
- } else if (Proxy.isProxyClass(obj.getClass())) {
- debugAppend(sb, Proxy.getInvocationHandler(obj));
- } else if (obj instanceof CharSequence) {
- sb.append("\"").append(obj.toString().replace('\n', '\u21b2')).append("\"");
- } else if (obj.getClass().isArray()) {
- sb.append(obj.getClass().getComponentType().getSimpleName()).append("[")
- .append(java.lang.reflect.Array.getLength(obj)).append("]");
- } else {
- sb.append(obj.toString());
- }
- return sb;
- }
-
- @Override
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- Object target;
- final Class<?> methodInterface = method.getDeclaringClass();
- if (DEBUG) {
- // Editable methods should all be called from the IC thread
- assertOnIcThread();
- }
- if (methodInterface == Editable.class ||
- methodInterface == Appendable.class ||
- methodInterface == Spannable.class) {
- // Method alters the Editable; route calls to our implementation
- target = this;
- } else {
- // Method queries the Editable; must sync with Gecko first
- // then call on the inner Editable itself
- mActionQueue.syncWithGecko();
- target = mText;
- }
- Object ret;
- try {
- ret = method.invoke(target, args);
- } catch (InvocationTargetException e) {
- // Bug 817386
- // Most likely Gecko has changed the text while GeckoInputConnection is
- // trying to access the text. If we pass through the exception here, Fennec
- // will crash due to a lack of exception handler. Log the exception and
- // return an empty value instead.
- if (!(e.getCause() instanceof IndexOutOfBoundsException)) {
- // Only handle IndexOutOfBoundsException for now,
- // as other exceptions might signal other bugs
- throw e;
- }
- Log.w(LOGTAG, "Exception in GeckoEditable." + method.getName(), e.getCause());
- Class<?> retClass = method.getReturnType();
- if (retClass == Character.TYPE) {
- ret = '\0';
- } else if (retClass == Integer.TYPE) {
- ret = 0;
- } else if (retClass == String.class) {
- ret = "";
- } else {
- ret = null;
- }
- }
- if (DEBUG) {
- StringBuilder log = new StringBuilder(method.getName());
- log.append("(");
- for (Object arg : args) {
- debugAppend(log, arg).append(", ");
- }
- if (args.length > 0) {
- log.setLength(log.length() - 2);
- }
- if (method.getReturnType().equals(Void.TYPE)) {
- log.append(")");
- } else {
- debugAppend(log.append(") = "), ret);
- }
- Log.d(LOGTAG, log.toString());
- }
- return ret;
- }
-
- // Spannable interface
-
- @Override
- public void removeSpan(Object what) {
- if (what == Selection.SELECTION_START ||
- what == Selection.SELECTION_END) {
- Log.w(LOGTAG, "selection removed with removeSpan()");
- }
- if (mText.getSpanStart(what) >= 0) { // only remove if it's there
- // Okay to remove immediately
- mText.removeSpan(what);
- mActionQueue.offer(new Action(Action.TYPE_REMOVE_SPAN));
- }
- }
-
- @Override
- public void setSpan(Object what, int start, int end, int flags) {
- if (what == Selection.SELECTION_START) {
- if ((flags & Spanned.SPAN_INTERMEDIATE) != 0) {
- // We will get the end offset next, just save the start for now
- mSavedSelectionStart = start;
- } else {
- mActionQueue.offer(Action.newSetSelection(start, -1));
- }
- } else if (what == Selection.SELECTION_END) {
- mActionQueue.offer(Action.newSetSelection(mSavedSelectionStart, end));
- mSavedSelectionStart = -1;
- } else {
- mActionQueue.offer(Action.newSetSpan(what, start, end, flags));
- }
- }
-
- // Appendable interface
-
- @Override
- public Editable append(CharSequence text) {
- return replace(mProxy.length(), mProxy.length(), text, 0, text.length());
- }
-
- @Override
- public Editable append(CharSequence text, int start, int end) {
- return replace(mProxy.length(), mProxy.length(), text, start, end);
- }
-
- @Override
- public Editable append(char text) {
- return replace(mProxy.length(), mProxy.length(), String.valueOf(text), 0, 1);
- }
-
- // Editable interface
-
- @Override
- public InputFilter[] getFilters() {
- return mFilters;
- }
-
- @Override
- public void setFilters(InputFilter[] filters) {
- mFilters = filters;
- }
-
- @Override
- public void clearSpans() {
- /* XXX this clears the selection spans too,
- but there is no way to clear the corresponding selection in Gecko */
- Log.w(LOGTAG, "selection cleared with clearSpans()");
- mText.clearSpans();
- }
-
- @Override
- public Editable replace(int st, int en,
- CharSequence source, int start, int end) {
-
- CharSequence text = source;
- if (start < 0 || start > end || end > text.length()) {
- throw new IllegalArgumentException("invalid replace offsets: " +
- start + " to " + end + ", length: " + text.length());
- }
- if (start != 0 || end != text.length()) {
- text = text.subSequence(start, end);
- }
- if (mFilters != null) {
- // Filter text before sending the request to Gecko
- for (int i = 0; i < mFilters.length; ++i) {
- final CharSequence cs = mFilters[i].filter(
- text, 0, text.length(), mProxy, st, en);
- if (cs != null) {
- text = cs;
- }
- }
- }
- if (text == source) {
- // Always create a copy
- text = new SpannableString(source);
- }
- mActionQueue.offer(Action.newReplaceText(text,
- Math.min(st, en), Math.max(st, en)));
- return mProxy;
- }
-
- @Override
- public void clear() {
- replace(0, mProxy.length(), "", 0, 0);
- }
-
- @Override
- public Editable delete(int st, int en) {
- return replace(st, en, "", 0, 0);
- }
-
- @Override
- public Editable insert(int where, CharSequence text,
- int start, int end) {
- return replace(where, where, text, start, end);
- }
-
- @Override
- public Editable insert(int where, CharSequence text) {
- return replace(where, where, text, 0, text.length());
- }
-
- @Override
- public Editable replace(int st, int en, CharSequence text) {
- return replace(st, en, text, 0, text.length());
- }
-
- /* GetChars interface */
-
- @Override
- public void getChars(int start, int end, char[] dest, int destoff) {
- /* overridden Editable interface methods in GeckoEditable must not be called directly
- outside of GeckoEditable. Instead, the call must go through mProxy, which ensures
- that Java is properly synchronized with Gecko */
- throw new UnsupportedOperationException("method must be called through mProxy");
- }
-
- /* Spanned interface */
-
- @Override
- public int getSpanEnd(Object tag) {
- throw new UnsupportedOperationException("method must be called through mProxy");
- }
-
- @Override
- public int getSpanFlags(Object tag) {
- throw new UnsupportedOperationException("method must be called through mProxy");
- }
-
- @Override
- public int getSpanStart(Object tag) {
- throw new UnsupportedOperationException("method must be called through mProxy");
- }
-
- @Override
- public <T> T[] getSpans(int start, int end, Class<T> type) {
- throw new UnsupportedOperationException("method must be called through mProxy");
- }
-
- @Override
- @SuppressWarnings("rawtypes") // nextSpanTransition uses raw Class in its Android declaration
- public int nextSpanTransition(int start, int limit, Class type) {
- throw new UnsupportedOperationException("method must be called through mProxy");
- }
-
- /* CharSequence interface */
-
- @Override
- public char charAt(int index) {
- throw new UnsupportedOperationException("method must be called through mProxy");
- }
-
- @Override
- public int length() {
- throw new UnsupportedOperationException("method must be called through mProxy");
- }
-
- @Override
- public CharSequence subSequence(int start, int end) {
- throw new UnsupportedOperationException("method must be called through mProxy");
- }
-
- @Override
- public String toString() {
- throw new UnsupportedOperationException("method must be called through mProxy");
- }
-}
-
diff --git a/mobile/android/base/GeckoEvent.java b/mobile/android/base/GeckoEvent.java
deleted file mode 100644
index b503ddbd7..000000000
--- a/mobile/android/base/GeckoEvent.java
+++ /dev/null
@@ -1,694 +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.gecko;
-
-import org.mozilla.gecko.gfx.DisplayPortMetrics;
-import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
-
-import android.content.res.Resources;
-import android.graphics.Point;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.hardware.Sensor;
-import android.hardware.SensorEvent;
-import android.hardware.SensorManager;
-import android.location.Address;
-import android.location.Location;
-import android.os.Build;
-import android.os.SystemClock;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-
-import java.nio.ByteBuffer;
-
-/* We're not allowed to hold on to most events given to us
- * so we save the parts of the events we want to use in GeckoEvent.
- * Fields have different meanings depending on the event type.
- */
-
-/* This class is referenced by Robocop via reflection; use care when
- * modifying the signature.
- */
-public class GeckoEvent {
- private static final String LOGTAG = "GeckoEvent";
-
- // Make sure to keep these values in sync with the enum in
- // AndroidGeckoEvent in widget/android/AndroidJavaWrapper.h
- private enum NativeGeckoEvent {
- NATIVE_POKE(0),
- KEY_EVENT(1),
- MOTION_EVENT(2),
- SENSOR_EVENT(3),
- LOCATION_EVENT(5),
- IME_EVENT(6),
- DRAW(7),
- SIZE_CHANGED(8),
- APP_BACKGROUNDING(9),
- APP_FOREGROUNDING(10),
- LOAD_URI(12),
- NOOP(15),
- BROADCAST(19),
- VIEWPORT(20),
- VISITED(21),
- NETWORK_CHANGED(22),
- THUMBNAIL(25),
- SCREENORIENTATION_CHANGED(27),
- COMPOSITOR_CREATE(28),
- COMPOSITOR_PAUSE(29),
- COMPOSITOR_RESUME(30),
- NATIVE_GESTURE_EVENT(31),
- IME_KEY_EVENT(32),
- CALL_OBSERVER(33),
- REMOVE_OBSERVER(34),
- LOW_MEMORY(35),
- NETWORK_LINK_CHANGE(36);
-
- public final int value;
-
- private NativeGeckoEvent(int value) {
- this.value = value;
- }
- }
-
- /**
- * The DomKeyLocation enum encapsulates the DOM KeyboardEvent's constants.
- * @see https://developer.mozilla.org/en-US/docs/DOM/KeyboardEvent#Key_location_constants
- */
- public enum DomKeyLocation {
- DOM_KEY_LOCATION_STANDARD(0),
- DOM_KEY_LOCATION_LEFT(1),
- DOM_KEY_LOCATION_RIGHT(2),
- DOM_KEY_LOCATION_NUMPAD(3),
- DOM_KEY_LOCATION_MOBILE(4),
- DOM_KEY_LOCATION_JOYSTICK(5);
-
- public final int value;
-
- private DomKeyLocation(int value) {
- this.value = value;
- }
- }
-
- // Encapsulation of common IME actions.
- public enum ImeAction {
- IME_SYNCHRONIZE(0),
- IME_REPLACE_TEXT(1),
- IME_SET_SELECTION(2),
- IME_ADD_COMPOSITION_RANGE(3),
- IME_UPDATE_COMPOSITION(4),
- IME_REMOVE_COMPOSITION(5),
- IME_ACKNOWLEDGE_FOCUS(6);
-
- public final int value;
-
- private ImeAction(int value) {
- this.value = value;
- }
- }
-
- public static final int IME_RANGE_CARETPOSITION = 1;
- public static final int IME_RANGE_RAWINPUT = 2;
- public static final int IME_RANGE_SELECTEDRAWTEXT = 3;
- public static final int IME_RANGE_CONVERTEDTEXT = 4;
- public static final int IME_RANGE_SELECTEDCONVERTEDTEXT = 5;
-
- public static final int IME_RANGE_LINE_NONE = 0;
- public static final int IME_RANGE_LINE_DOTTED = 1;
- public static final int IME_RANGE_LINE_DASHED = 2;
- public static final int IME_RANGE_LINE_SOLID = 3;
- public static final int IME_RANGE_LINE_DOUBLE = 4;
- public static final int IME_RANGE_LINE_WAVY = 5;
-
- public static final int IME_RANGE_UNDERLINE = 1;
- public static final int IME_RANGE_FORECOLOR = 2;
- public static final int IME_RANGE_BACKCOLOR = 4;
- public static final int IME_RANGE_LINECOLOR = 8;
-
- public static final int ACTION_MAGNIFY_START = 11;
- public static final int ACTION_MAGNIFY = 12;
- public static final int ACTION_MAGNIFY_END = 13;
-
- private final int mType;
- private int mAction;
- private boolean mAckNeeded;
- private long mTime;
- private Point[] mPoints;
- private int[] mPointIndicies;
- private int mPointerIndex; // index of the point that has changed
- private float[] mOrientations;
- private float[] mPressures;
- private Point[] mPointRadii;
- private Rect mRect;
- private double mX;
- private double mY;
- private double mZ;
-
- private int mMetaState;
- private int mFlags;
- private int mKeyCode;
- private int mUnicodeChar;
- private int mBaseUnicodeChar; // mUnicodeChar without meta states applied
- private int mRepeatCount;
- private int mCount;
- private int mStart;
- private int mEnd;
- private String mCharacters;
- private String mCharactersExtra;
- private String mData;
- private int mRangeType;
- private int mRangeStyles;
- private int mRangeLineStyle;
- private boolean mRangeBoldLine;
- private int mRangeForeColor;
- private int mRangeBackColor;
- private int mRangeLineColor;
- private Location mLocation;
- private Address mAddress;
- private DomKeyLocation mDomKeyLocation;
-
- private double mBandwidth;
- private boolean mCanBeMetered;
-
- private int mNativeWindow;
-
- private short mScreenOrientation;
-
- private ByteBuffer mBuffer;
-
- private int mWidth;
- private int mHeight;
-
- private GeckoEvent(NativeGeckoEvent event) {
- mType = event.value;
- }
-
- public static GeckoEvent createAppBackgroundingEvent() {
- return new GeckoEvent(NativeGeckoEvent.APP_BACKGROUNDING);
- }
-
- public static GeckoEvent createAppForegroundingEvent() {
- return new GeckoEvent(NativeGeckoEvent.APP_FOREGROUNDING);
- }
-
- public static GeckoEvent createNoOpEvent() {
- return new GeckoEvent(NativeGeckoEvent.NOOP);
- }
-
- public static GeckoEvent createKeyEvent(KeyEvent k, int metaState) {
- GeckoEvent event = new GeckoEvent(NativeGeckoEvent.KEY_EVENT);
- event.initKeyEvent(k, metaState);
- return event;
- }
-
- public static GeckoEvent createCompositorCreateEvent(int width, int height) {
- GeckoEvent event = new GeckoEvent(NativeGeckoEvent.COMPOSITOR_CREATE);
- event.mWidth = width;
- event.mHeight = height;
- return event;
- }
-
- public static GeckoEvent createCompositorPauseEvent() {
- return new GeckoEvent(NativeGeckoEvent.COMPOSITOR_PAUSE);
- }
-
- public static GeckoEvent createCompositorResumeEvent() {
- return new GeckoEvent(NativeGeckoEvent.COMPOSITOR_RESUME);
- }
-
- private void initKeyEvent(KeyEvent k, int metaState) {
- mAction = k.getAction();
- mTime = k.getEventTime();
- // Normally we expect k.getMetaState() to reflect the current meta-state; however,
- // some software-generated key events may not have k.getMetaState() set, e.g. key
- // events from Swype. Therefore, it's necessary to combine the key's meta-states
- // with the meta-states that we keep separately in KeyListener
- mMetaState = k.getMetaState() | metaState;
- mFlags = k.getFlags();
- mKeyCode = k.getKeyCode();
- mUnicodeChar = k.getUnicodeChar(mMetaState);
- // e.g. for Ctrl+A, Android returns 0 for mUnicodeChar,
- // but Gecko expects 'a', so we return that in mBaseUnicodeChar
- mBaseUnicodeChar = k.getUnicodeChar(0);
- mRepeatCount = k.getRepeatCount();
- mCharacters = k.getCharacters();
- mDomKeyLocation = isJoystickButton(mKeyCode) ? DomKeyLocation.DOM_KEY_LOCATION_JOYSTICK
- : DomKeyLocation.DOM_KEY_LOCATION_MOBILE;
- }
-
- /**
- * This method tests if a key is one of the described in:
- * https://bugzilla.mozilla.org/show_bug.cgi?id=756504#c0
- * @param keyCode int with the key code (Android key constant from KeyEvent)
- * @return true if the key is one of the listed above, false otherwise.
- */
- private static boolean isJoystickButton(int keyCode) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_DPAD_CENTER:
- case KeyEvent.KEYCODE_DPAD_LEFT:
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- case KeyEvent.KEYCODE_DPAD_DOWN:
- case KeyEvent.KEYCODE_DPAD_UP:
- return true;
- default:
- if (Build.VERSION.SDK_INT >= 12) {
- return KeyEvent.isGamepadButton(keyCode);
- }
- return GeckoEvent.isGamepadButton(keyCode);
- }
- }
-
- /**
- * This method is a replacement for the the KeyEvent.isGamepadButton method to be
- * compatible with Build.VERSION.SDK_INT < 12. This is an implementantion of the
- * same method isGamepadButton available after SDK 12.
- * @param keyCode int with the key code (Android key constant from KeyEvent).
- * @return True if the keycode is a gamepad button, such as {@link #KEYCODE_BUTTON_A}.
- */
- private static boolean isGamepadButton(int keyCode) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_BUTTON_A:
- case KeyEvent.KEYCODE_BUTTON_B:
- case KeyEvent.KEYCODE_BUTTON_C:
- case KeyEvent.KEYCODE_BUTTON_X:
- case KeyEvent.KEYCODE_BUTTON_Y:
- case KeyEvent.KEYCODE_BUTTON_Z:
- case KeyEvent.KEYCODE_BUTTON_L1:
- case KeyEvent.KEYCODE_BUTTON_R1:
- case KeyEvent.KEYCODE_BUTTON_L2:
- case KeyEvent.KEYCODE_BUTTON_R2:
- case KeyEvent.KEYCODE_BUTTON_THUMBL:
- case KeyEvent.KEYCODE_BUTTON_THUMBR:
- case KeyEvent.KEYCODE_BUTTON_START:
- case KeyEvent.KEYCODE_BUTTON_SELECT:
- case KeyEvent.KEYCODE_BUTTON_MODE:
- case KeyEvent.KEYCODE_BUTTON_1:
- case KeyEvent.KEYCODE_BUTTON_2:
- case KeyEvent.KEYCODE_BUTTON_3:
- case KeyEvent.KEYCODE_BUTTON_4:
- case KeyEvent.KEYCODE_BUTTON_5:
- case KeyEvent.KEYCODE_BUTTON_6:
- case KeyEvent.KEYCODE_BUTTON_7:
- case KeyEvent.KEYCODE_BUTTON_8:
- case KeyEvent.KEYCODE_BUTTON_9:
- case KeyEvent.KEYCODE_BUTTON_10:
- case KeyEvent.KEYCODE_BUTTON_11:
- case KeyEvent.KEYCODE_BUTTON_12:
- case KeyEvent.KEYCODE_BUTTON_13:
- case KeyEvent.KEYCODE_BUTTON_14:
- case KeyEvent.KEYCODE_BUTTON_15:
- case KeyEvent.KEYCODE_BUTTON_16:
- return true;
- default:
- return false;
- }
- }
-
- public static GeckoEvent createNativeGestureEvent(int action, PointF pt, double size) {
- try {
- GeckoEvent event = new GeckoEvent(NativeGeckoEvent.NATIVE_GESTURE_EVENT);
- event.mAction = action;
- event.mCount = 1;
- event.mPoints = new Point[1];
-
- PointF geckoPoint = new PointF(pt.x, pt.y);
- geckoPoint = GeckoAppShell.getLayerView().convertViewPointToLayerPoint(geckoPoint);
-
- if (geckoPoint == null) {
- // This could happen if Gecko isn't ready yet.
- return null;
- }
-
- event.mPoints[0] = new Point(Math.round(geckoPoint.x), Math.round(geckoPoint.y));
-
- event.mX = size;
- event.mTime = System.currentTimeMillis();
- return event;
- } catch (Exception e) {
- // This can happen if Gecko isn't ready yet
- return null;
- }
- }
-
- /**
- * Creates a GeckoEvent that contains the data from the MotionEvent.
- * The keepInViewCoordinates parameter can be set to false to convert from the Java
- * coordinate system (device pixels relative to the LayerView) to a coordinate system
- * relative to gecko's coordinate system (CSS pixels relative to gecko scroll position).
- */
- public static GeckoEvent createMotionEvent(MotionEvent m, boolean keepInViewCoordinates) {
- GeckoEvent event = new GeckoEvent(NativeGeckoEvent.MOTION_EVENT);
- event.initMotionEvent(m, keepInViewCoordinates);
- return event;
- }
-
- private void initMotionEvent(MotionEvent m, boolean keepInViewCoordinates) {
- mAction = m.getActionMasked();
- mTime = (System.currentTimeMillis() - SystemClock.elapsedRealtime()) + m.getEventTime();
- mMetaState = m.getMetaState();
-
- switch (mAction) {
- case MotionEvent.ACTION_CANCEL:
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_POINTER_UP:
- case MotionEvent.ACTION_POINTER_DOWN:
- case MotionEvent.ACTION_DOWN:
- case MotionEvent.ACTION_MOVE:
- case MotionEvent.ACTION_HOVER_ENTER:
- case MotionEvent.ACTION_HOVER_MOVE:
- case MotionEvent.ACTION_HOVER_EXIT: {
- mCount = m.getPointerCount();
- mPoints = new Point[mCount];
- mPointIndicies = new int[mCount];
- mOrientations = new float[mCount];
- mPressures = new float[mCount];
- mPointRadii = new Point[mCount];
- mPointerIndex = m.getActionIndex();
- for (int i = 0; i < mCount; i++) {
- addMotionPoint(i, i, m, keepInViewCoordinates);
- }
- break;
- }
- default: {
- mCount = 0;
- mPointerIndex = -1;
- mPoints = new Point[mCount];
- mPointIndicies = new int[mCount];
- mOrientations = new float[mCount];
- mPressures = new float[mCount];
- mPointRadii = new Point[mCount];
- }
- }
- }
-
- private void addMotionPoint(int index, int eventIndex, MotionEvent event, boolean keepInViewCoordinates) {
- try {
- PointF geckoPoint = new PointF(event.getX(eventIndex), event.getY(eventIndex));
- if (!keepInViewCoordinates) {
- geckoPoint = GeckoAppShell.getLayerView().convertViewPointToLayerPoint(geckoPoint);
- }
-
- mPoints[index] = new Point(Math.round(geckoPoint.x), Math.round(geckoPoint.y));
- mPointIndicies[index] = event.getPointerId(eventIndex);
- // getToolMajor, getToolMinor and getOrientation are API Level 9 features
- if (Build.VERSION.SDK_INT >= 9) {
- double radians = event.getOrientation(eventIndex);
- mOrientations[index] = (float) Math.toDegrees(radians);
- // w3c touchevents spec does not allow orientations == 90
- // this shifts it to -90, which will be shifted to zero below
- if (mOrientations[index] == 90)
- mOrientations[index] = -90;
-
- // w3c touchevent radius are given by an orientation between 0 and 90
- // the radius is found by removing the orientation and measuring the x and y
- // radius of the resulting ellipse
- // for android orientations >= 0 and < 90, the major axis should correspond to
- // just reporting the y radius as the major one, and x as minor
- // however, for a radius < 0, we have to shift the orientation by adding 90, and
- // reverse which radius is major and minor
- if (mOrientations[index] < 0) {
- mOrientations[index] += 90;
- mPointRadii[index] = new Point((int)event.getToolMajor(eventIndex)/2,
- (int)event.getToolMinor(eventIndex)/2);
- } else {
- mPointRadii[index] = new Point((int)event.getToolMinor(eventIndex)/2,
- (int)event.getToolMajor(eventIndex)/2);
- }
- } else {
- float size = event.getSize(eventIndex);
- Resources resources = GeckoAppShell.getContext().getResources();
- DisplayMetrics displaymetrics = resources.getDisplayMetrics();
- size = size*Math.min(displaymetrics.heightPixels, displaymetrics.widthPixels);
- mPointRadii[index] = new Point((int)size,(int)size);
- mOrientations[index] = 0;
- }
- mPressures[index] = event.getPressure(eventIndex);
- } catch (Exception ex) {
- Log.e(LOGTAG, "Error creating motion point " + index, ex);
- mPointRadii[index] = new Point(0, 0);
- mPoints[index] = new Point(0, 0);
- }
- }
-
- private static int HalSensorAccuracyFor(int androidAccuracy) {
- switch (androidAccuracy) {
- case SensorManager.SENSOR_STATUS_UNRELIABLE:
- return GeckoHalDefines.SENSOR_ACCURACY_UNRELIABLE;
- case SensorManager.SENSOR_STATUS_ACCURACY_LOW:
- return GeckoHalDefines.SENSOR_ACCURACY_LOW;
- case SensorManager.SENSOR_STATUS_ACCURACY_MEDIUM:
- return GeckoHalDefines.SENSOR_ACCURACY_MED;
- case SensorManager.SENSOR_STATUS_ACCURACY_HIGH:
- return GeckoHalDefines.SENSOR_ACCURACY_HIGH;
- }
- return GeckoHalDefines.SENSOR_ACCURACY_UNKNOWN;
- }
-
- public static GeckoEvent createSensorEvent(SensorEvent s) {
- int sensor_type = s.sensor.getType();
- GeckoEvent event = null;
-
- switch(sensor_type) {
-
- case Sensor.TYPE_ACCELEROMETER:
- event = new GeckoEvent(NativeGeckoEvent.SENSOR_EVENT);
- event.mFlags = GeckoHalDefines.SENSOR_ACCELERATION;
- event.mMetaState = HalSensorAccuracyFor(s.accuracy);
- event.mX = s.values[0];
- event.mY = s.values[1];
- event.mZ = s.values[2];
- break;
-
- case 10 /* Requires API Level 9, so just use the raw value - Sensor.TYPE_LINEAR_ACCELEROMETER*/ :
- event = new GeckoEvent(NativeGeckoEvent.SENSOR_EVENT);
- event.mFlags = GeckoHalDefines.SENSOR_LINEAR_ACCELERATION;
- event.mMetaState = HalSensorAccuracyFor(s.accuracy);
- event.mX = s.values[0];
- event.mY = s.values[1];
- event.mZ = s.values[2];
- break;
-
- case Sensor.TYPE_ORIENTATION:
- event = new GeckoEvent(NativeGeckoEvent.SENSOR_EVENT);
- event.mFlags = GeckoHalDefines.SENSOR_ORIENTATION;
- event.mMetaState = HalSensorAccuracyFor(s.accuracy);
- event.mX = s.values[0];
- event.mY = s.values[1];
- event.mZ = s.values[2];
- break;
-
- case Sensor.TYPE_GYROSCOPE:
- event = new GeckoEvent(NativeGeckoEvent.SENSOR_EVENT);
- event.mFlags = GeckoHalDefines.SENSOR_GYROSCOPE;
- event.mMetaState = HalSensorAccuracyFor(s.accuracy);
- event.mX = Math.toDegrees(s.values[0]);
- event.mY = Math.toDegrees(s.values[1]);
- event.mZ = Math.toDegrees(s.values[2]);
- break;
-
- case Sensor.TYPE_PROXIMITY:
- event = new GeckoEvent(NativeGeckoEvent.SENSOR_EVENT);
- event.mFlags = GeckoHalDefines.SENSOR_PROXIMITY;
- event.mMetaState = HalSensorAccuracyFor(s.accuracy);
- event.mX = s.values[0];
- event.mY = 0;
- event.mZ = s.sensor.getMaximumRange();
- break;
-
- case Sensor.TYPE_LIGHT:
- event = new GeckoEvent(NativeGeckoEvent.SENSOR_EVENT);
- event.mFlags = GeckoHalDefines.SENSOR_LIGHT;
- event.mMetaState = HalSensorAccuracyFor(s.accuracy);
- event.mX = s.values[0];
- break;
- }
- return event;
- }
-
- public static GeckoEvent createLocationEvent(Location l) {
- GeckoEvent event = new GeckoEvent(NativeGeckoEvent.LOCATION_EVENT);
- event.mLocation = l;
- return event;
- }
-
- public static GeckoEvent createIMEEvent(ImeAction action) {
- GeckoEvent event = new GeckoEvent(NativeGeckoEvent.IME_EVENT);
- event.mAction = action.value;
- return event;
- }
-
- public static GeckoEvent createIMEKeyEvent(KeyEvent k) {
- GeckoEvent event = new GeckoEvent(NativeGeckoEvent.IME_KEY_EVENT);
- event.initKeyEvent(k, 0);
- return event;
- }
-
- public static GeckoEvent createIMEReplaceEvent(int start, int end,
- String text) {
- GeckoEvent event = new GeckoEvent(NativeGeckoEvent.IME_EVENT);
- event.mAction = ImeAction.IME_REPLACE_TEXT.value;
- event.mStart = start;
- event.mEnd = end;
- event.mCharacters = text;
- return event;
- }
-
- public static GeckoEvent createIMESelectEvent(int start, int end) {
- GeckoEvent event = new GeckoEvent(NativeGeckoEvent.IME_EVENT);
- event.mAction = ImeAction.IME_SET_SELECTION.value;
- event.mStart = start;
- event.mEnd = end;
- return event;
- }
-
- public static GeckoEvent createIMECompositionEvent(int start, int end) {
- GeckoEvent event = new GeckoEvent(NativeGeckoEvent.IME_EVENT);
- event.mAction = ImeAction.IME_UPDATE_COMPOSITION.value;
- event.mStart = start;
- event.mEnd = end;
- return event;
- }
-
- public static GeckoEvent createIMERangeEvent(int start,
- int end, int rangeType,
- int rangeStyles,
- int rangeLineStyle,
- boolean rangeBoldLine,
- int rangeForeColor,
- int rangeBackColor,
- int rangeLineColor) {
- GeckoEvent event = new GeckoEvent(NativeGeckoEvent.IME_EVENT);
- event.mAction = ImeAction.IME_ADD_COMPOSITION_RANGE.value;
- event.mStart = start;
- event.mEnd = end;
- event.mRangeType = rangeType;
- event.mRangeStyles = rangeStyles;
- event.mRangeLineStyle = rangeLineStyle;
- event.mRangeBoldLine = rangeBoldLine;
- event.mRangeForeColor = rangeForeColor;
- event.mRangeBackColor = rangeBackColor;
- event.mRangeLineColor = rangeLineColor;
- return event;
- }
-
- public static GeckoEvent createDrawEvent(Rect rect) {
- GeckoEvent event = new GeckoEvent(NativeGeckoEvent.DRAW);
- event.mRect = rect;
- return event;
- }
-
- public static GeckoEvent createSizeChangedEvent(int w, int h, int screenw, int screenh) {
- GeckoEvent event = new GeckoEvent(NativeGeckoEvent.SIZE_CHANGED);
- event.mPoints = new Point[2];
- event.mPoints[0] = new Point(w, h);
- event.mPoints[1] = new Point(screenw, screenh);
- return event;
- }
-
- public static GeckoEvent createBroadcastEvent(String subject, String data) {
- GeckoEvent event = new GeckoEvent(NativeGeckoEvent.BROADCAST);
- event.mCharacters = subject;
- event.mCharactersExtra = data;
- return event;
- }
-
- public static GeckoEvent createViewportEvent(ImmutableViewportMetrics metrics, DisplayPortMetrics displayPort) {
- GeckoEvent event = new GeckoEvent(NativeGeckoEvent.VIEWPORT);
- event.mCharacters = "Viewport:Change";
- StringBuffer sb = new StringBuffer(256);
- sb.append("{ \"x\" : ").append(metrics.viewportRectLeft)
- .append(", \"y\" : ").append(metrics.viewportRectTop)
- .append(", \"zoom\" : ").append(metrics.zoomFactor)
- .append(", \"fixedMarginLeft\" : ").append(metrics.marginLeft)
- .append(", \"fixedMarginTop\" : ").append(metrics.marginTop)
- .append(", \"fixedMarginRight\" : ").append(metrics.marginRight)
- .append(", \"fixedMarginBottom\" : ").append(metrics.marginBottom)
- .append(", \"displayPort\" :").append(displayPort.toJSON())
- .append('}');
- event.mCharactersExtra = sb.toString();
- return event;
- }
-
- public static GeckoEvent createURILoadEvent(String uri) {
- GeckoEvent event = new GeckoEvent(NativeGeckoEvent.LOAD_URI);
- event.mCharacters = uri;
- event.mCharactersExtra = "";
- return event;
- }
-
- public static GeckoEvent createWebappLoadEvent(String uri) {
- GeckoEvent event = new GeckoEvent(NativeGeckoEvent.LOAD_URI);
- event.mCharacters = uri;
- event.mCharactersExtra = "-webapp";
- return event;
- }
-
- public static GeckoEvent createBookmarkLoadEvent(String uri) {
- GeckoEvent event = new GeckoEvent(NativeGeckoEvent.LOAD_URI);
- event.mCharacters = uri;
- event.mCharactersExtra = "-bookmark";
- return event;
- }
-
- public static GeckoEvent createVisitedEvent(String data) {
- GeckoEvent event = new GeckoEvent(NativeGeckoEvent.VISITED);
- event.mCharacters = data;
- return event;
- }
-
- public static GeckoEvent createNetworkEvent(double bandwidth, boolean canBeMetered) {
- GeckoEvent event = new GeckoEvent(NativeGeckoEvent.NETWORK_CHANGED);
- event.mBandwidth = bandwidth;
- event.mCanBeMetered = canBeMetered;
- return event;
- }
-
- public static GeckoEvent createThumbnailEvent(int tabId, int bufw, int bufh, ByteBuffer buffer) {
- GeckoEvent event = new GeckoEvent(NativeGeckoEvent.THUMBNAIL);
- event.mPoints = new Point[1];
- event.mPoints[0] = new Point(bufw, bufh);
- event.mMetaState = tabId;
- event.mBuffer = buffer;
- return event;
- }
-
- public static GeckoEvent createScreenOrientationEvent(short aScreenOrientation) {
- GeckoEvent event = new GeckoEvent(NativeGeckoEvent.SCREENORIENTATION_CHANGED);
- event.mScreenOrientation = aScreenOrientation;
- return event;
- }
-
- public static GeckoEvent createCallObserverEvent(String observerKey, String topic, String data) {
- GeckoEvent event = new GeckoEvent(NativeGeckoEvent.CALL_OBSERVER);
- event.mCharacters = observerKey;
- event.mCharactersExtra = topic;
- event.mData = data;
- return event;
- }
-
- public static GeckoEvent createRemoveObserverEvent(String observerKey) {
- GeckoEvent event = new GeckoEvent(NativeGeckoEvent.REMOVE_OBSERVER);
- event.mCharacters = observerKey;
- return event;
- }
-
- public static GeckoEvent createLowMemoryEvent(int level) {
- GeckoEvent event = new GeckoEvent(NativeGeckoEvent.LOW_MEMORY);
- event.mMetaState = level;
- return event;
- }
-
- public static GeckoEvent createNetworkLinkChangeEvent(String status) {
- GeckoEvent event = new GeckoEvent(NativeGeckoEvent.NETWORK_LINK_CHANGE);
- event.mCharacters = status;
- return event;
- }
-
- public void setAckNeeded(boolean ackNeeded) {
- mAckNeeded = ackNeeded;
- }
-}
diff --git a/mobile/android/base/GeckoHalDefines.java b/mobile/android/base/GeckoHalDefines.java
deleted file mode 100644
index 3ebe47028..000000000
--- a/mobile/android/base/GeckoHalDefines.java
+++ /dev/null
@@ -1,25 +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.gecko;
-
-public class GeckoHalDefines
-{
- /*
- * Keep these values consistent with |SensorType| in Hal.h
- */
- public static final int SENSOR_ORIENTATION = 0;
- public static final int SENSOR_ACCELERATION = 1;
- public static final int SENSOR_PROXIMITY = 2;
- public static final int SENSOR_LINEAR_ACCELERATION = 3;
- public static final int SENSOR_GYROSCOPE = 4;
- public static final int SENSOR_LIGHT = 5;
-
- public static final int SENSOR_ACCURACY_UNKNOWN = -1;
- public static final int SENSOR_ACCURACY_UNRELIABLE = 0;
- public static final int SENSOR_ACCURACY_LOW = 1;
- public static final int SENSOR_ACCURACY_MED = 2;
- public static final int SENSOR_ACCURACY_HIGH = 3;
-};
diff --git a/mobile/android/base/GeckoInputConnection.java b/mobile/android/base/GeckoInputConnection.java
deleted file mode 100644
index fcc45f8da..000000000
--- a/mobile/android/base/GeckoInputConnection.java
+++ /dev/null
@@ -1,1032 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; 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.gecko;
-
-import org.mozilla.gecko.gfx.InputConnectionHandler;
-import org.mozilla.gecko.util.Clipboard;
-import org.mozilla.gecko.util.GamepadUtils;
-import org.mozilla.gecko.util.ThreadUtils;
-
-import android.R;
-import android.content.Context;
-import android.os.Build;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.SystemClock;
-import android.text.Editable;
-import android.text.InputType;
-import android.text.Selection;
-import android.text.SpannableString;
-import android.text.method.KeyListener;
-import android.text.method.TextKeyListener;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.inputmethod.BaseInputConnection;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.ExtractedText;
-import android.view.inputmethod.ExtractedTextRequest;
-import android.view.inputmethod.InputConnection;
-import android.view.inputmethod.InputMethodManager;
-
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-import java.util.concurrent.SynchronousQueue;
-
-class GeckoInputConnection
- extends BaseInputConnection
- implements InputConnectionHandler, GeckoEditableListener {
-
- private static final boolean DEBUG = false;
- protected static final String LOGTAG = "GeckoInputConnection";
-
- private static final int INLINE_IME_MIN_DISPLAY_SIZE = 480;
-
- private static Handler sBackgroundHandler;
-
- private static class InputThreadUtils {
- // We only want one UI editable around to keep synchronization simple,
- // so we make InputThreadUtils a singleton
- public static final InputThreadUtils sInstance = new InputThreadUtils();
-
- private Editable mUiEditable;
- private Object mUiEditableReturn;
- private Exception mUiEditableException;
- private final SynchronousQueue<Runnable> mIcRunnableSync;
- private final Runnable mIcSignalRunnable;
-
- private InputThreadUtils() {
- mIcRunnableSync = new SynchronousQueue<Runnable>();
- mIcSignalRunnable = new Runnable() {
- @Override public void run() {
- }
- };
- }
-
- private void runOnIcThread(Handler icHandler, final Runnable runnable) {
- if (DEBUG) {
- ThreadUtils.assertOnUiThread();
- Log.d(LOGTAG, "runOnIcThread() on thread " +
- icHandler.getLooper().getThread().getName());
- }
- Runnable runner = new Runnable() {
- @Override public void run() {
- try {
- Runnable queuedRunnable = mIcRunnableSync.take();
- if (DEBUG && queuedRunnable != runnable) {
- throw new IllegalThreadStateException("sync error");
- }
- queuedRunnable.run();
- } catch (InterruptedException e) {
- }
- }
- };
- try {
- // if we are not inside waitForUiThread(), runner will call the runnable
- icHandler.post(runner);
- // runnable will be called by either runner from above or waitForUiThread()
- mIcRunnableSync.put(runnable);
- } catch (InterruptedException e) {
- } finally {
- // if waitForUiThread() already called runnable, runner should not call it again
- icHandler.removeCallbacks(runner);
- }
- }
-
- public void endWaitForUiThread() {
- if (DEBUG) {
- ThreadUtils.assertOnUiThread();
- Log.d(LOGTAG, "endWaitForUiThread()");
- }
- try {
- mIcRunnableSync.put(mIcSignalRunnable);
- } catch (InterruptedException e) {
- }
- }
-
- public void waitForUiThread(Handler icHandler) {
- if (DEBUG) {
- ThreadUtils.assertOnThread(icHandler.getLooper().getThread());
- Log.d(LOGTAG, "waitForUiThread() blocking on thread " +
- icHandler.getLooper().getThread().getName());
- }
- try {
- Runnable runnable = null;
- do {
- runnable = mIcRunnableSync.take();
- runnable.run();
- } while (runnable != mIcSignalRunnable);
- } catch (InterruptedException e) {
- }
- }
-
- public void runOnIcThread(final Handler uiHandler,
- final GeckoEditableClient client,
- final Runnable runnable) {
- final Handler icHandler = client.getInputConnectionHandler();
- if (icHandler.getLooper() == uiHandler.getLooper()) {
- // IC thread is UI thread; safe to run directly
- runnable.run();
- return;
- }
- runOnIcThread(icHandler, runnable);
- }
-
- public Editable getEditableForUiThread(final Handler uiHandler,
- final GeckoEditableClient client) {
- if (DEBUG) {
- ThreadUtils.assertOnThread(uiHandler.getLooper().getThread());
- }
- final Handler icHandler = client.getInputConnectionHandler();
- if (icHandler.getLooper() == uiHandler.getLooper()) {
- // IC thread is UI thread; safe to use Editable directly
- return client.getEditable();
- }
- // IC thread is not UI thread; we need to return a proxy Editable in order
- // to safely use the Editable from the UI thread
- if (mUiEditable != null) {
- return mUiEditable;
- }
- final InvocationHandler invokeEditable = new InvocationHandler() {
- @Override public Object invoke(final Object proxy,
- final Method method,
- final Object[] args) throws Throwable {
- if (DEBUG) {
- ThreadUtils.assertOnThread(uiHandler.getLooper().getThread());
- Log.d(LOGTAG, "UiEditable." + method.getName() + "() blocking");
- }
- synchronized (icHandler) {
- // Now we are on UI thread
- mUiEditableReturn = null;
- mUiEditableException = null;
- // Post a Runnable that calls the real Editable and saves any
- // result/exception. Then wait on the Runnable to finish
- runOnIcThread(icHandler, new Runnable() {
- @Override public void run() {
- synchronized (icHandler) {
- try {
- mUiEditableReturn = method.invoke(
- client.getEditable(), args);
- } catch (Exception e) {
- mUiEditableException = e;
- }
- if (DEBUG) {
- Log.d(LOGTAG, "UiEditable." + method.getName() +
- "() returning");
- }
- icHandler.notify();
- }
- }
- });
- // let InterruptedException propagate
- icHandler.wait();
- if (mUiEditableException != null) {
- throw mUiEditableException;
- }
- return mUiEditableReturn;
- }
- }
- };
- mUiEditable = (Editable) Proxy.newProxyInstance(Editable.class.getClassLoader(),
- new Class<?>[] { Editable.class }, invokeEditable);
- return mUiEditable;
- }
- }
-
- // Managed only by notifyIMEContext; see comments in notifyIMEContext
- private int mIMEState;
- private String mIMETypeHint = "";
- private String mIMEModeHint = "";
- private String mIMEActionHint = "";
-
- private String mCurrentInputMethod = "";
-
- private final GeckoEditableClient mEditableClient;
- protected int mBatchEditCount;
- private ExtractedTextRequest mUpdateRequest;
- private final ExtractedText mUpdateExtract = new ExtractedText();
- private boolean mBatchSelectionChanged;
- private boolean mBatchTextChanged;
- private long mLastRestartInputTime;
- private final InputConnection mKeyInputConnection;
-
- public static GeckoEditableListener create(View targetView,
- GeckoEditableClient editable) {
- if (DEBUG)
- return DebugGeckoInputConnection.create(targetView, editable);
- else
- return new GeckoInputConnection(targetView, editable);
- }
-
- protected GeckoInputConnection(View targetView,
- GeckoEditableClient editable) {
- super(targetView, true);
- mEditableClient = editable;
- mIMEState = IME_STATE_DISABLED;
- // InputConnection that sends keys for plugins, which don't have full editors
- mKeyInputConnection = new BaseInputConnection(targetView, false);
- }
-
- @Override
- public synchronized boolean beginBatchEdit() {
- mBatchEditCount++;
- mEditableClient.setUpdateGecko(false);
- return true;
- }
-
- @Override
- public synchronized boolean endBatchEdit() {
- if (mBatchEditCount > 0) {
- mBatchEditCount--;
- if (mBatchEditCount == 0) {
- if (mBatchTextChanged) {
- notifyTextChange();
- mBatchTextChanged = false;
- }
- if (mBatchSelectionChanged) {
- Editable editable = getEditable();
- notifySelectionChange(Selection.getSelectionStart(editable),
- Selection.getSelectionEnd(editable));
- mBatchSelectionChanged = false;
- }
- mEditableClient.setUpdateGecko(true);
- }
- } else {
- Log.w(LOGTAG, "endBatchEdit() called, but mBatchEditCount == 0?!");
- }
- return true;
- }
-
- @Override
- public Editable getEditable() {
- return mEditableClient.getEditable();
- }
-
- @Override
- public boolean performContextMenuAction(int id) {
- Editable editable = getEditable();
- if (editable == null) {
- return false;
- }
- int selStart = Selection.getSelectionStart(editable);
- int selEnd = Selection.getSelectionEnd(editable);
-
- switch (id) {
- case R.id.selectAll:
- setSelection(0, editable.length());
- break;
- case R.id.cut:
- // If selection is empty, we'll select everything
- if (selStart == selEnd) {
- // Fill the clipboard
- Clipboard.setText(editable);
- editable.clear();
- } else {
- Clipboard.setText(
- editable.toString().substring(
- Math.min(selStart, selEnd),
- Math.max(selStart, selEnd)));
- editable.delete(selStart, selEnd);
- }
- break;
- case R.id.paste:
- commitText(Clipboard.getText(), 1);
- break;
- case R.id.copy:
- // Copy the current selection or the empty string if nothing is selected.
- String copiedText = selStart == selEnd ? "" :
- editable.toString().substring(
- Math.min(selStart, selEnd),
- Math.max(selStart, selEnd));
- Clipboard.setText(copiedText);
- break;
- }
- return true;
- }
-
- @Override
- public ExtractedText getExtractedText(ExtractedTextRequest req, int flags) {
- if (req == null)
- return null;
-
- if ((flags & GET_EXTRACTED_TEXT_MONITOR) != 0)
- mUpdateRequest = req;
-
- Editable editable = getEditable();
- if (editable == null) {
- return null;
- }
- int selStart = Selection.getSelectionStart(editable);
- int selEnd = Selection.getSelectionEnd(editable);
-
- ExtractedText extract = new ExtractedText();
- extract.flags = 0;
- extract.partialStartOffset = -1;
- extract.partialEndOffset = -1;
- extract.selectionStart = selStart;
- extract.selectionEnd = selEnd;
- extract.startOffset = 0;
- if ((req.flags & GET_TEXT_WITH_STYLES) != 0) {
- extract.text = new SpannableString(editable);
- } else {
- extract.text = editable.toString();
- }
- return extract;
- }
-
- private static View getView() {
- return GeckoAppShell.getLayerView();
- }
-
- private static InputMethodManager getInputMethodManager() {
- View view = getView();
- if (view == null) {
- return null;
- }
- Context context = view.getContext();
- return InputMethods.getInputMethodManager(context);
- }
-
- private static void showSoftInput() {
- final InputMethodManager imm = getInputMethodManager();
- if (imm != null) {
- final View v = getView();
- imm.showSoftInput(v, 0);
- }
- }
-
- private static void hideSoftInput() {
- final InputMethodManager imm = getInputMethodManager();
- if (imm != null) {
- final View v = getView();
- imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
- }
- }
-
- private void tryRestartInput() {
- // Coalesce restartInput calls because InputMethodManager.restartInput()
- // is expensive and successive calls to it can lock up the keyboard
- if (SystemClock.uptimeMillis() < mLastRestartInputTime + 200) {
- return;
- }
- restartInput();
- }
-
- private void restartInput() {
-
- mLastRestartInputTime = SystemClock.uptimeMillis();
-
- final InputMethodManager imm = getInputMethodManager();
- if (imm == null) {
- return;
- }
- final View v = getView();
- // InputMethodManager has internal logic to detect if we are restarting input
- // in an already focused View, which is the case here because all content text
- // fields are inside one LayerView. When this happens, InputMethodManager will
- // tell the input method to soft reset instead of hard reset. Stock latin IME
- // on Android 4.2+ has a quirk that when it soft resets, it does not clear the
- // composition. The following workaround tricks the IME into clearing the
- // composition when soft resetting.
- if (InputMethods.needsSoftResetWorkaround(mCurrentInputMethod)) {
- // Fake a selection change, because the IME clears the composition when
- // the selection changes, even if soft-resetting. Offsets here must be
- // different from the previous selection offsets, and -1 seems to be a
- // reasonable, deterministic value
- notifySelectionChange(-1, -1);
- }
- imm.restartInput(v);
- }
-
- private void resetInputConnection() {
- if (mBatchEditCount != 0) {
- Log.w(LOGTAG, "resetting with mBatchEditCount = " + mBatchEditCount);
- mBatchEditCount = 0;
- }
- mBatchSelectionChanged = false;
- mBatchTextChanged = false;
-
- // Do not reset mIMEState here; see comments in notifyIMEContext
- }
-
- @Override
- public void onTextChange(String text, int start, int oldEnd, int newEnd) {
-
- if (mUpdateRequest == null) {
- return;
- }
-
- if (mBatchEditCount > 0) {
- // Delay notification until after the batch edit
- mBatchTextChanged = true;
- return;
- }
- notifyTextChange();
- }
-
- private void notifyTextChange() {
-
- final InputMethodManager imm = getInputMethodManager();
- final View v = getView();
- final Editable editable = getEditable();
- if (imm == null || v == null || editable == null) {
- return;
- }
- mUpdateExtract.flags = 0;
- // Update the entire Editable range
- mUpdateExtract.partialStartOffset = -1;
- mUpdateExtract.partialEndOffset = -1;
- mUpdateExtract.selectionStart =
- Selection.getSelectionStart(editable);
- mUpdateExtract.selectionEnd =
- Selection.getSelectionEnd(editable);
- mUpdateExtract.startOffset = 0;
- if ((mUpdateRequest.flags & GET_TEXT_WITH_STYLES) != 0) {
- mUpdateExtract.text = new SpannableString(editable);
- } else {
- mUpdateExtract.text = editable.toString();
- }
- imm.updateExtractedText(v, mUpdateRequest.token,
- mUpdateExtract);
- }
-
- @Override
- public void onSelectionChange(int start, int end) {
-
- if (mBatchEditCount > 0) {
- // Delay notification until after the batch edit
- mBatchSelectionChanged = true;
- return;
- }
- notifySelectionChange(start, end);
- }
-
- private void notifySelectionChange(int start, int end) {
-
- final InputMethodManager imm = getInputMethodManager();
- final View v = getView();
- final Editable editable = getEditable();
- if (imm == null || v == null || editable == null) {
- return;
- }
- imm.updateSelection(v, start, end, getComposingSpanStart(editable),
- getComposingSpanEnd(editable));
- }
-
- private static synchronized Handler getBackgroundHandler() {
- if (sBackgroundHandler != null) {
- return sBackgroundHandler;
- }
- // Don't use GeckoBackgroundThread because Gecko thread may block waiting on
- // GeckoBackgroundThread. If we were to use GeckoBackgroundThread, due to IME,
- // GeckoBackgroundThread may end up also block waiting on Gecko thread and a
- // deadlock occurs
- Thread backgroundThread = new Thread(new Runnable() {
- @Override
- public void run() {
- Looper.prepare();
- synchronized (GeckoInputConnection.class) {
- sBackgroundHandler = new Handler();
- GeckoInputConnection.class.notify();
- }
- Looper.loop();
- sBackgroundHandler = null;
- }
- }, LOGTAG);
- backgroundThread.setDaemon(true);
- backgroundThread.start();
- while (sBackgroundHandler == null) {
- try {
- // wait for new thread to set sBackgroundHandler
- GeckoInputConnection.class.wait();
- } catch (InterruptedException e) {
- }
- }
- return sBackgroundHandler;
- }
-
- private boolean canReturnCustomHandler() {
- if (mIMEState == IME_STATE_DISABLED) {
- return false;
- }
- for (StackTraceElement frame : Thread.currentThread().getStackTrace()) {
- // We only return our custom Handler to InputMethodManager's InputConnection
- // proxy. For all other purposes, we return the regular Handler.
- // InputMethodManager retrieves the Handler for its InputConnection proxy
- // inside its method startInputInner(), so we check for that here. This is
- // valid from Android 2.2 to at least Android 4.2. If this situation ever
- // changes, we gracefully fall back to using the regular Handler.
- if ("startInputInner".equals(frame.getMethodName()) &&
- "android.view.inputmethod.InputMethodManager".equals(frame.getClassName())) {
- // only return our own Handler to InputMethodManager
- return true;
- }
- }
- return false;
- }
-
- @Override
- public Handler getHandler(Handler defHandler) {
- if (!canReturnCustomHandler()) {
- return defHandler;
- }
- // getBackgroundHandler() is synchronized and requires locking,
- // but if we already have our handler, we don't have to lock
- final Handler newHandler = sBackgroundHandler != null
- ? sBackgroundHandler
- : getBackgroundHandler();
- if (mEditableClient.setInputConnectionHandler(newHandler)) {
- return newHandler;
- }
- // Setting new IC handler failed; return old IC handler
- return mEditableClient.getInputConnectionHandler();
- }
-
- @Override
- public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
- if (mIMEState == IME_STATE_DISABLED) {
- return null;
- }
-
- outAttrs.inputType = InputType.TYPE_CLASS_TEXT;
- outAttrs.imeOptions = EditorInfo.IME_ACTION_NONE;
- outAttrs.actionLabel = null;
-
- if (mIMEState == IME_STATE_PASSWORD ||
- "password".equalsIgnoreCase(mIMETypeHint))
- outAttrs.inputType |= InputType.TYPE_TEXT_VARIATION_PASSWORD;
- else if (mIMEState == IME_STATE_PLUGIN)
- outAttrs.inputType = InputType.TYPE_NULL; // "send key events" mode
- else if (mIMETypeHint.equalsIgnoreCase("url"))
- outAttrs.inputType |= InputType.TYPE_TEXT_VARIATION_URI;
- else if (mIMETypeHint.equalsIgnoreCase("email"))
- outAttrs.inputType |= InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
- else if (mIMETypeHint.equalsIgnoreCase("search"))
- outAttrs.imeOptions = EditorInfo.IME_ACTION_SEARCH;
- else if (mIMETypeHint.equalsIgnoreCase("tel"))
- outAttrs.inputType = InputType.TYPE_CLASS_PHONE;
- else if (mIMETypeHint.equalsIgnoreCase("number") ||
- mIMETypeHint.equalsIgnoreCase("range"))
- outAttrs.inputType = InputType.TYPE_CLASS_NUMBER
- | InputType.TYPE_NUMBER_FLAG_SIGNED
- | InputType.TYPE_NUMBER_FLAG_DECIMAL;
- else if (mIMETypeHint.equalsIgnoreCase("week") ||
- mIMETypeHint.equalsIgnoreCase("month"))
- outAttrs.inputType = InputType.TYPE_CLASS_DATETIME
- | InputType.TYPE_DATETIME_VARIATION_DATE;
- else if (mIMEModeHint.equalsIgnoreCase("numeric"))
- outAttrs.inputType = InputType.TYPE_CLASS_NUMBER |
- InputType.TYPE_NUMBER_FLAG_SIGNED |
- InputType.TYPE_NUMBER_FLAG_DECIMAL;
- else if (mIMEModeHint.equalsIgnoreCase("digit"))
- outAttrs.inputType = InputType.TYPE_CLASS_NUMBER;
- else {
- // TYPE_TEXT_FLAG_IME_MULTI_LINE flag makes the fullscreen IME line wrap
- outAttrs.inputType |= InputType.TYPE_TEXT_FLAG_AUTO_CORRECT |
- InputType.TYPE_TEXT_FLAG_IME_MULTI_LINE;
- if (mIMETypeHint.equalsIgnoreCase("textarea") ||
- mIMETypeHint.length() == 0) {
- // empty mIMETypeHint indicates contentEditable/designMode documents
- outAttrs.inputType |= InputType.TYPE_TEXT_FLAG_MULTI_LINE;
- }
- if (mIMEModeHint.equalsIgnoreCase("uppercase"))
- outAttrs.inputType |= InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS;
- else if (mIMEModeHint.equalsIgnoreCase("titlecase"))
- outAttrs.inputType |= InputType.TYPE_TEXT_FLAG_CAP_WORDS;
- else if (mIMEModeHint.equalsIgnoreCase("autocapitalized"))
- outAttrs.inputType |= InputType.TYPE_TEXT_FLAG_CAP_SENTENCES;
- // lowercase mode is the default
- }
-
- if (mIMEActionHint.equalsIgnoreCase("go"))
- outAttrs.imeOptions = EditorInfo.IME_ACTION_GO;
- else if (mIMEActionHint.equalsIgnoreCase("done"))
- outAttrs.imeOptions = EditorInfo.IME_ACTION_DONE;
- else if (mIMEActionHint.equalsIgnoreCase("next"))
- outAttrs.imeOptions = EditorInfo.IME_ACTION_NEXT;
- else if (mIMEActionHint.equalsIgnoreCase("search"))
- outAttrs.imeOptions = EditorInfo.IME_ACTION_SEARCH;
- else if (mIMEActionHint.equalsIgnoreCase("send"))
- outAttrs.imeOptions = EditorInfo.IME_ACTION_SEND;
- else if (mIMEActionHint.length() > 0) {
- if (DEBUG)
- Log.w(LOGTAG, "Unexpected mIMEActionHint=\"" + mIMEActionHint + "\"");
- outAttrs.actionLabel = mIMEActionHint;
- }
-
- Context context = GeckoAppShell.getContext();
- DisplayMetrics metrics = context.getResources().getDisplayMetrics();
- if (Math.min(metrics.widthPixels, metrics.heightPixels) > INLINE_IME_MIN_DISPLAY_SIZE) {
- // prevent showing full-screen keyboard only when the screen is tall enough
- // to show some reasonable amount of the page (see bug 752709)
- outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_EXTRACT_UI
- | EditorInfo.IME_FLAG_NO_FULLSCREEN;
- }
-
- if (DEBUG) {
- Log.d(LOGTAG, "mapped IME states to: inputType = " +
- Integer.toHexString(outAttrs.inputType) + ", imeOptions = " +
- Integer.toHexString(outAttrs.imeOptions));
- }
-
- String prevInputMethod = mCurrentInputMethod;
- mCurrentInputMethod = InputMethods.getCurrentInputMethod(context);
- if (DEBUG) {
- Log.d(LOGTAG, "IME: CurrentInputMethod=" + mCurrentInputMethod);
- }
-
- // If the user has changed IMEs, then notify input method observers.
- if (!mCurrentInputMethod.equals(prevInputMethod) && GeckoAppShell.getGeckoInterface() != null) {
- FormAssistPopup popup = GeckoAppShell.getGeckoInterface().getFormAssistPopup();
- if (popup != null) {
- popup.onInputMethodChanged(mCurrentInputMethod);
- }
- }
-
- if (mIMEState == IME_STATE_PLUGIN) {
- // Since we are using a temporary string as the editable, the selection is at 0
- outAttrs.initialSelStart = 0;
- outAttrs.initialSelEnd = 0;
- return mKeyInputConnection;
- }
- Editable editable = getEditable();
- outAttrs.initialSelStart = Selection.getSelectionStart(editable);
- outAttrs.initialSelEnd = Selection.getSelectionEnd(editable);
- return this;
- }
-
- private boolean replaceComposingSpanWithSelection() {
- final Editable content = getEditable();
- if (content == null) {
- return false;
- }
- int a = getComposingSpanStart(content),
- b = getComposingSpanEnd(content);
- if (a != -1 && b != -1) {
- if (DEBUG) {
- Log.d(LOGTAG, "removing composition at " + a + "-" + b);
- }
- removeComposingSpans(content);
- Selection.setSelection(content, a, b);
- }
- return true;
- }
-
- @Override
- public boolean commitText(CharSequence text, int newCursorPosition) {
- if (InputMethods.shouldCommitCharAsKey(mCurrentInputMethod) &&
- text.length() == 1 && newCursorPosition > 0) {
- if (DEBUG) {
- Log.d(LOGTAG, "committing \"" + text + "\" as key");
- }
- // mKeyInputConnection is a BaseInputConnection that commits text as keys;
- // but we first need to replace any composing span with a selection,
- // so that the new key events will generate characters to replace
- // text from the old composing span
- return replaceComposingSpanWithSelection() &&
- mKeyInputConnection.commitText(text, newCursorPosition);
- }
- return super.commitText(text, newCursorPosition);
- }
-
- @Override
- public boolean setSelection(int start, int end) {
- if (start < 0 || end < 0) {
- // Some keyboards (e.g. Samsung) can call setSelection with
- // negative offsets. In that case we ignore the call, similar to how
- // BaseInputConnection.setSelection ignores offsets that go past the length.
- return true;
- }
- return super.setSelection(start, end);
- }
-
- @Override
- public boolean sendKeyEvent(KeyEvent event) {
- // BaseInputConnection.sendKeyEvent() dispatches the key event to the main thread.
- // In order to ensure events are processed in the proper order, we must block the
- // IC thread until the main thread finishes processing the key event
- super.sendKeyEvent(event);
- final View v = getView();
- if (v == null) {
- return false;
- }
- final Handler icHandler = mEditableClient.getInputConnectionHandler();
- final Handler mainHandler = v.getRootView().getHandler();
- if (icHandler.getLooper() != mainHandler.getLooper()) {
- // We are on separate IC thread but the event is queued on the main thread;
- // wait on IC thread until the main thread processes our posted Runnable. At
- // that point the key event has already been processed.
- mainHandler.post(new Runnable() {
- @Override public void run() {
- InputThreadUtils.sInstance.endWaitForUiThread();
- }
- });
- InputThreadUtils.sInstance.waitForUiThread(icHandler);
- }
- return false; // seems to always return false
- }
-
- @Override
- public boolean onKeyPreIme(int keyCode, KeyEvent event) {
- return false;
- }
-
- private boolean shouldProcessKey(int keyCode, KeyEvent event) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_MENU:
- case KeyEvent.KEYCODE_BACK:
- case KeyEvent.KEYCODE_VOLUME_UP:
- case KeyEvent.KEYCODE_VOLUME_DOWN:
- case KeyEvent.KEYCODE_SEARCH:
- return false;
- }
- return true;
- }
-
- private boolean shouldSkipKeyListener(int keyCode, KeyEvent event) {
- if (mIMEState == IME_STATE_DISABLED ||
- mIMEState == IME_STATE_PLUGIN) {
- return true;
- }
- // Preserve enter and tab keys for the browser
- if (keyCode == KeyEvent.KEYCODE_ENTER ||
- keyCode == KeyEvent.KEYCODE_TAB) {
- return true;
- }
- // BaseKeyListener returns false even if it handled these keys for us,
- // so we skip the key listener entirely and handle these ourselves
- if (keyCode == KeyEvent.KEYCODE_DEL ||
- keyCode == KeyEvent.KEYCODE_FORWARD_DEL) {
- return true;
- }
- return false;
- }
-
- private KeyEvent translateKey(int keyCode, KeyEvent event) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_ENTER:
- if ((event.getFlags() & KeyEvent.FLAG_EDITOR_ACTION) != 0 &&
- mIMEActionHint.equalsIgnoreCase("next")) {
- return new KeyEvent(event.getAction(), KeyEvent.KEYCODE_TAB);
- }
- break;
- }
- return event;
- }
-
- private boolean processKey(int keyCode, KeyEvent event, boolean down) {
- if (GamepadUtils.isSonyXperiaGamepadKeyEvent(event)) {
- event = GamepadUtils.translateSonyXperiaGamepadKeys(keyCode, event);
- keyCode = event.getKeyCode();
- }
-
- if (keyCode > KeyEvent.getMaxKeyCode() ||
- !shouldProcessKey(keyCode, event)) {
- return false;
- }
- event = translateKey(keyCode, event);
- keyCode = event.getKeyCode();
-
- View view = getView();
- if (view == null) {
- mEditableClient.sendEvent(GeckoEvent.createKeyEvent(event, 0));
- return true;
- }
-
- // KeyListener returns true if it handled the event for us. KeyListener is only
- // safe to use on the UI thread; therefore we need to pass a proxy Editable to it
- KeyListener keyListener = TextKeyListener.getInstance();
- Handler uiHandler = view.getRootView().getHandler();
- Editable uiEditable = InputThreadUtils.sInstance.
- getEditableForUiThread(uiHandler, mEditableClient);
- boolean skip = shouldSkipKeyListener(keyCode, event);
- if (down) {
- mEditableClient.setSuppressKeyUp(true);
- }
- if (skip ||
- (down && !keyListener.onKeyDown(view, uiEditable, keyCode, event)) ||
- (!down && !keyListener.onKeyUp(view, uiEditable, keyCode, event))) {
- mEditableClient.sendEvent(
- GeckoEvent.createKeyEvent(event, TextKeyListener.getMetaState(uiEditable)));
- if (skip && down) {
- // Usually, the down key listener call above adjusts meta states for us.
- // However, if we skip that call above, we have to manually adjust meta
- // states so the meta states remain consistent
- TextKeyListener.adjustMetaAfterKeypress(uiEditable);
- }
- }
- if (down) {
- mEditableClient.setSuppressKeyUp(false);
- }
- return true;
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- return processKey(keyCode, event, true);
- }
-
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- return processKey(keyCode, event, false);
- }
-
- @Override
- public boolean onKeyMultiple(int keyCode, int repeatCount, final KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_UNKNOWN) {
- // KEYCODE_UNKNOWN means the characters are in KeyEvent.getCharacters()
- View view = getView();
- if (view != null) {
- InputThreadUtils.sInstance.runOnIcThread(
- view.getRootView().getHandler(), mEditableClient,
- new Runnable() {
- @Override public void run() {
- // Don't call GeckoInputConnection.commitText because it can
- // post a key event back to onKeyMultiple, causing a loop
- GeckoInputConnection.super.commitText(event.getCharacters(), 1);
- }
- });
- }
- return true;
- }
- while ((repeatCount--) != 0) {
- if (!processKey(keyCode, event, true) ||
- !processKey(keyCode, event, false)) {
- return false;
- }
- }
- return true;
- }
-
- @Override
- public boolean onKeyLongPress(int keyCode, KeyEvent event) {
- View v = getView();
- switch (keyCode) {
- case KeyEvent.KEYCODE_MENU:
- InputMethodManager imm = getInputMethodManager();
- imm.toggleSoftInputFromWindow(v.getWindowToken(),
- InputMethodManager.SHOW_FORCED, 0);
- return true;
- default:
- break;
- }
- return false;
- }
-
- @Override
- public boolean isIMEEnabled() {
- // make sure this picks up PASSWORD and PLUGIN states as well
- return mIMEState != IME_STATE_DISABLED;
- }
-
- @Override
- public void notifyIME(int type) {
- switch (type) {
-
- case NOTIFY_IME_TO_CANCEL_COMPOSITION:
- // Set composition to empty and end composition
- setComposingText("", 0);
- // Fall through
-
- case NOTIFY_IME_TO_COMMIT_COMPOSITION:
- // Commit and end composition
- finishComposingText();
- tryRestartInput();
- break;
-
- case NOTIFY_IME_OF_FOCUS:
- case NOTIFY_IME_OF_BLUR:
- // Showing/hiding vkb is done in notifyIMEContext
- resetInputConnection();
- break;
-
- default:
- if (DEBUG) {
- throw new IllegalArgumentException("Unexpected NOTIFY_IME=" + type);
- }
- break;
- }
- }
-
- @Override
- public void notifyIMEContext(int state, String typeHint, String modeHint, String actionHint) {
- // For some input type we will use a widget to display the ui, for those we must not
- // display the ime. We can display a widget for date and time types and, if the sdk version
- // is 11 or greater, for datetime/month/week as well.
- if (typeHint != null &&
- (typeHint.equalsIgnoreCase("date") ||
- typeHint.equalsIgnoreCase("time") ||
- (Build.VERSION.SDK_INT >= 11 && (typeHint.equalsIgnoreCase("datetime") ||
- typeHint.equalsIgnoreCase("month") ||
- typeHint.equalsIgnoreCase("week") ||
- typeHint.equalsIgnoreCase("datetime-local"))))) {
- state = IME_STATE_DISABLED;
- }
-
- // mIMEState and the mIME*Hint fields should only be changed by notifyIMEContext,
- // and not reset anywhere else. Usually, notifyIMEContext is called right after a
- // focus or blur, so resetting mIMEState during the focus or blur seems harmless.
- // However, this behavior is not guaranteed. Gecko may call notifyIMEContext
- // independent of focus change; that is, a focus change may not be accompanied by
- // a notifyIMEContext call. So if we reset mIMEState inside focus, there may not
- // be another notifyIMEContext call to set mIMEState to a proper value (bug 829318)
- /* When IME is 'disabled', IME processing is disabled.
- In addition, the IME UI is hidden */
- mIMEState = state;
- mIMETypeHint = (typeHint == null) ? "" : typeHint;
- mIMEModeHint = (modeHint == null) ? "" : modeHint;
- mIMEActionHint = (actionHint == null) ? "" : actionHint;
-
- // These fields are reset here and will be updated when restartInput is called below
- mUpdateRequest = null;
- mCurrentInputMethod = "";
-
- View v = getView();
- if (v == null || !v.hasFocus()) {
- // When using Find In Page, we can still receive notifyIMEContext calls due to the
- // selection changing when highlighting. However in this case we don't want to reset/
- // show/hide the keyboard because the find box has the focus and is taking input from
- // the keyboard.
- return;
- }
- restartInput();
- if (mIMEState == IME_STATE_DISABLED) {
- hideSoftInput();
- } else {
- showSoftInput();
- }
- }
-}
-
-final class DebugGeckoInputConnection
- extends GeckoInputConnection
- implements InvocationHandler {
-
- private InputConnection mProxy;
- private StringBuilder mCallLevel;
-
- private DebugGeckoInputConnection(View targetView,
- GeckoEditableClient editable) {
- super(targetView, editable);
- mCallLevel = new StringBuilder();
- }
-
- public static GeckoEditableListener create(View targetView,
- GeckoEditableClient editable) {
- final Class[] PROXY_INTERFACES = { InputConnection.class,
- InputConnectionHandler.class,
- GeckoEditableListener.class };
- DebugGeckoInputConnection dgic =
- new DebugGeckoInputConnection(targetView, editable);
- dgic.mProxy = (InputConnection)Proxy.newProxyInstance(
- GeckoInputConnection.class.getClassLoader(),
- PROXY_INTERFACES, dgic);
- return (GeckoEditableListener)dgic.mProxy;
- }
-
- @Override
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
-
- StringBuilder log = new StringBuilder(mCallLevel);
- log.append("> ").append(method.getName()).append("(");
- for (Object arg : args) {
- // translate argument values to constant names
- if ("notifyIME".equals(method.getName()) && arg == args[0]) {
- log.append(GeckoEditable.getConstantName(
- GeckoEditableListener.class, "NOTIFY_IME_", arg));
- } else if ("notifyIMEContext".equals(method.getName()) && arg == args[0]) {
- log.append(GeckoEditable.getConstantName(
- GeckoEditableListener.class, "IME_STATE_", arg));
- } else {
- GeckoEditable.debugAppend(log, arg);
- }
- log.append(", ");
- }
- if (args.length > 0) {
- log.setLength(log.length() - 2);
- }
- log.append(")");
- Log.d(LOGTAG, log.toString());
-
- mCallLevel.append(' ');
- Object ret = method.invoke(this, args);
- if (ret == this) {
- ret = mProxy;
- }
- mCallLevel.setLength(Math.max(0, mCallLevel.length() - 1));
-
- log.setLength(mCallLevel.length());
- log.append("< ").append(method.getName());
- if (!method.getReturnType().equals(Void.TYPE)) {
- GeckoEditable.debugAppend(log.append(": "), ret);
- }
- Log.d(LOGTAG, log.toString());
- return ret;
- }
-}
diff --git a/mobile/android/base/GeckoJavaSampler.java b/mobile/android/base/GeckoJavaSampler.java
deleted file mode 100644
index 130d5643f..000000000
--- a/mobile/android/base/GeckoJavaSampler.java
+++ /dev/null
@@ -1,184 +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.gecko;
-
-import android.util.Log;
-import java.lang.Thread;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-public class GeckoJavaSampler {
- private static final String LOGTAG = "JavaSampler";
- private static Thread sSamplingThread = null;
- private static SamplingThread sSamplingRunnable = null;
- private static Thread sMainThread = null;
-
- // Use the same timer primitive as the profiler
- // to get a perfect sample syncing.
- private static native double getProfilerTime();
-
- private static class Sample {
- public Frame[] mFrames;
- public double mTime;
- public Sample(StackTraceElement[] aStack) {
- mFrames = new Frame[aStack.length];
- mTime = getProfilerTime();
- for (int i = 0; i < aStack.length; i++) {
- mFrames[aStack.length - 1 - i] = new Frame();
- mFrames[aStack.length - 1 - i].fileName = aStack[i].getFileName();
- mFrames[aStack.length - 1 - i].lineNo = aStack[i].getLineNumber();
- mFrames[aStack.length - 1 - i].methodName = aStack[i].getMethodName();
- mFrames[aStack.length - 1 - i].className = aStack[i].getClassName();
- }
- }
- }
- private static class Frame {
- public String fileName;
- public int lineNo;
- public String methodName;
- public String className;
- }
-
- private static class SamplingThread implements Runnable {
- private final int mInterval;
- private final int mSampleCount;
-
- private boolean mPauseSampler = false;
- private boolean mStopSampler = false;
-
- private Map<Integer,Sample[]> mSamples = new HashMap<Integer,Sample[]>();
- private int mSamplePos;
-
- public SamplingThread(final int aInterval, final int aSampleCount) {
- // If we sample faster then 10ms we get to many missed samples
- mInterval = Math.max(10, aInterval);
- mSampleCount = aSampleCount;
- }
-
- public void run() {
- synchronized (GeckoJavaSampler.class) {
- mSamples.put(0, new Sample[mSampleCount]);
- mSamplePos = 0;
-
- // Find the main thread
- Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
- for (Thread t : threadSet) {
- if (t.getName().compareToIgnoreCase("main") == 0) {
- sMainThread = t;
- break;
- }
- }
-
- if (sMainThread == null) {
- Log.e(LOGTAG, "Main thread not found");
- return;
- }
- }
-
- while (true) {
- try {
- Thread.sleep(mInterval);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- synchronized (GeckoJavaSampler.class) {
- if (!mPauseSampler) {
- StackTraceElement[] bt = sMainThread.getStackTrace();
- mSamples.get(0)[mSamplePos] = new Sample(bt);
- mSamplePos = (mSamplePos+1) % mSamples.get(0).length;
- }
- if (mStopSampler) {
- break;
- }
- }
- }
- }
-
- private Sample getSample(int aThreadId, int aSampleId) {
- if (aThreadId < mSamples.size() && aSampleId < mSamples.get(aThreadId).length &&
- mSamples.get(aThreadId)[aSampleId] != null) {
- int startPos = 0;
- if (mSamples.get(aThreadId)[mSamplePos] != null) {
- startPos = mSamplePos;
- }
- int readPos = (startPos + aSampleId) % mSamples.get(aThreadId).length;
- return mSamples.get(aThreadId)[readPos];
- }
- return null;
- }
- }
-
- public synchronized static String getThreadName(int aThreadId) {
- if (aThreadId == 0 && sMainThread != null) {
- return sMainThread.getName();
- }
- return null;
- }
-
- private synchronized static Sample getSample(int aThreadId, int aSampleId) {
- return sSamplingRunnable.getSample(aThreadId, aSampleId);
- }
- public synchronized static double getSampleTime(int aThreadId, int aSampleId) {
- Sample sample = getSample(aThreadId, aSampleId);
- if (sample != null) {
- System.out.println("Sample: " + sample.mTime);
- return sample.mTime;
- }
- return 0;
- }
- public synchronized static String getFrameName(int aThreadId, int aSampleId, int aFrameId) {
- Sample sample = getSample(aThreadId, aSampleId);
- if (sample != null && aFrameId < sample.mFrames.length) {
- Frame frame = sample.mFrames[aFrameId];
- if (frame == null) {
- return null;
- }
- return frame.className + "." + frame.methodName + "()";
- }
- return null;
- }
-
- public static void start(int aInterval, int aSamples) {
- synchronized (GeckoJavaSampler.class) {
- sSamplingRunnable = new SamplingThread(aInterval, aSamples);
- sSamplingThread = new Thread(sSamplingRunnable, "Java Sampler");
- sSamplingThread.start();
- }
- }
-
- public static void pause() {
- synchronized (GeckoJavaSampler.class) {
- sSamplingRunnable.mPauseSampler = true;
- }
- }
-
- public static void unpause() {
- synchronized (GeckoJavaSampler.class) {
- sSamplingRunnable.mPauseSampler = false;
- }
- }
-
- public static void stop() {
- synchronized (GeckoJavaSampler.class) {
- if (sSamplingThread == null) {
- return;
- }
-
- sSamplingRunnable.mStopSampler = true;
- try {
- sSamplingThread.join();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- sSamplingThread = null;
- sSamplingRunnable = null;
- }
- }
-}
-
-
-
diff --git a/mobile/android/base/GeckoMessageReceiver.java b/mobile/android/base/GeckoMessageReceiver.java
deleted file mode 100644
index 2c31d6c61..000000000
--- a/mobile/android/base/GeckoMessageReceiver.java
+++ /dev/null
@@ -1,19 +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/. */
-
-package org.mozilla.gecko;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-
-public class GeckoMessageReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (GeckoApp.ACTION_INIT_PW.equals(action)) {
- GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Passwords:Init", null));
- }
- }
-}
diff --git a/mobile/android/base/GeckoNetworkManager.java b/mobile/android/base/GeckoNetworkManager.java
deleted file mode 100644
index 5ec493463..000000000
--- a/mobile/android/base/GeckoNetworkManager.java
+++ /dev/null
@@ -1,297 +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.gecko;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.telephony.TelephonyManager;
-import android.util.Log;
-
-/*
- * A part of the work of GeckoNetworkManager is to give an estimation of the
- * download speed of the current connection. For known to be fast connection, we
- * simply use a predefined value (we don't care about being precise). For mobile
- * connections, we sort them in groups (generations) and estimate the average
- * real life download speed of that specific generation. This value comes from
- * researches (eg. Wikipedia articles) or is simply an arbitrary estimation.
- * Precision isn't important, we mostly need an order of magnitude.
- *
- * Each group is composed with networks represented by the constant from
- * Android's ConnectivityManager and the description comming from the same
- * class.
- *
- * 2G (15 bk/s):
- * int NETWORK_TYPE_IDEN Current network is iDen
- * int NETWORK_TYPE_CDMA Current network is CDMA: Either IS95A or IS95B
- *
- * 2.5G (60 kb/s)
- * int NETWORK_TYPE_GPRS Current network is GPRS
- * int NETWORK_TYPE_1xRTT Current network is 1xRTT
- *
- * 2.75G (200 kb/s)
- * int NETWORK_TYPE_EDGE Current network is EDGE
- *
- * 3G (300 kb/s)
- * int NETWORK_TYPE_UMTS Current network is UMTS
- * int NETWORK_TYPE_EVDO_0 Current network is EVDO revision 0
- *
- * 3.5G (7 Mb/s)
- * int NETWORK_TYPE_HSPA Current network is HSPA
- * int NETWORK_TYPE_HSDPA Current network is HSDPA
- * int NETWORK_TYPE_HSUPA Current network is HSUPA
- * int NETWORK_TYPE_EVDO_A Current network is EVDO revision A
- * int NETWORK_TYPE_EVDO_B Current network is EVDO revision B
- * int NETWORK_TYPE_EHRPD Current network is eHRPD
- *
- * 3.75G (20 Mb/s)
- * int NETWORK_TYPE_HSPAP Current network is HSPA+
- *
- * 3.9G (50 Mb/s)
- * int NETWORK_TYPE_LTE Current network is LTE
- */
-
-public class GeckoNetworkManager extends BroadcastReceiver {
- private static final String LOGTAG = "GeckoNetworkManager";
-
- static private final GeckoNetworkManager sInstance = new GeckoNetworkManager();
-
- static private final double kDefaultBandwidth = -1.0;
- static private final boolean kDefaultCanBeMetered = false;
-
- static private final double kMaxBandwidth = 20.0;
-
- static private final double kNetworkSpeedEthernet = 20.0; // 20 Mb/s
- static private final double kNetworkSpeedWifi = 20.0; // 20 Mb/s
- static private final double kNetworkSpeedWiMax = 40.0; // 40 Mb/s
- static private final double kNetworkSpeed_2_G = 15.0 / 1024.0; // 15 kb/s
- static private final double kNetworkSpeed_2_5_G = 60.0 / 1024.0; // 60 kb/s
- static private final double kNetworkSpeed_2_75_G = 200.0 / 1024.0; // 200 kb/s
- static private final double kNetworkSpeed_3_G = 300.0 / 1024.0; // 300 kb/s
- static private final double kNetworkSpeed_3_5_G = 7.0; // 7 Mb/s
- static private final double kNetworkSpeed_3_75_G = 20.0; // 20 Mb/s
- static private final double kNetworkSpeed_3_9_G = 50.0; // 50 Mb/s
-
- private enum NetworkType {
- NETWORK_NONE,
- NETWORK_ETHERNET,
- NETWORK_WIFI,
- NETWORK_WIMAX,
- NETWORK_2_G, // 2G
- NETWORK_2_5_G, // 2.5G
- NETWORK_2_75_G, // 2.75G
- NETWORK_3_G, // 3G
- NETWORK_3_5_G, // 3.5G
- NETWORK_3_75_G, // 3.75G
- NETWORK_3_9_G, // 3.9G
- NETWORK_UNKNOWN
- }
-
- private Context mApplicationContext;
- private NetworkType mNetworkType = NetworkType.NETWORK_NONE;
- private IntentFilter mNetworkFilter = new IntentFilter();
- // Whether the manager should be listening to Network Information changes.
- private boolean mShouldBeListening = false;
- // Whether the manager should notify Gecko that a change in Network
- // Information happened.
- private boolean mShouldNotify = false;
-
- public static GeckoNetworkManager getInstance() {
- return sInstance;
- }
-
- @Override
- public void onReceive(Context aContext, Intent aIntent) {
- updateNetworkType();
- }
-
- public void init(Context context) {
- mApplicationContext = context.getApplicationContext();
- mNetworkFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
- mNetworkType = getNetworkType();
- }
-
- public void start() {
- mShouldBeListening = true;
- updateNetworkType();
-
- if (mShouldNotify) {
- startListening();
- }
- }
-
- private void startListening() {
- mApplicationContext.registerReceiver(sInstance, mNetworkFilter);
- }
-
- public void stop() {
- mShouldBeListening = false;
-
- if (mShouldNotify) {
- stopListening();
- }
- }
-
- private void stopListening() {
- mApplicationContext.unregisterReceiver(sInstance);
- }
-
- private void updateNetworkType() {
- NetworkType previousNetworkType = mNetworkType;
- mNetworkType = getNetworkType();
-
- if (mNetworkType == previousNetworkType || !mShouldNotify) {
- return;
- }
-
- GeckoAppShell.sendEventToGecko(GeckoEvent.createNetworkEvent(
- getNetworkSpeed(mNetworkType),
- isNetworkUsuallyMetered(mNetworkType)));
- }
-
- public double[] getCurrentInformation() {
- return new double[] { getNetworkSpeed(mNetworkType),
- isNetworkUsuallyMetered(mNetworkType) ? 1.0 : 0.0 };
- }
-
- public void enableNotifications() {
- // We set mShouldNotify *after* calling updateNetworkType() to make sure we
- // don't notify an eventual change in mNetworkType.
- updateNetworkType();
- mShouldNotify = true;
-
- if (mShouldBeListening) {
- startListening();
- }
- }
-
- public void disableNotifications() {
- mShouldNotify = false;
-
- if (mShouldBeListening) {
- stopListening();
- }
- }
-
- private static NetworkType getNetworkType() {
- ConnectivityManager cm =
- (ConnectivityManager)sInstance.mApplicationContext.getSystemService(Context.CONNECTIVITY_SERVICE);
- if (cm == null) {
- Log.e(LOGTAG, "Connectivity service does not exist");
- return NetworkType.NETWORK_NONE;
- }
-
- NetworkInfo ni = cm.getActiveNetworkInfo();
- if (ni == null) {
- return NetworkType.NETWORK_NONE;
- }
-
- switch (ni.getType()) {
- case ConnectivityManager.TYPE_ETHERNET:
- return NetworkType.NETWORK_ETHERNET;
- case ConnectivityManager.TYPE_WIFI:
- return NetworkType.NETWORK_WIFI;
- case ConnectivityManager.TYPE_WIMAX:
- return NetworkType.NETWORK_WIMAX;
- case ConnectivityManager.TYPE_MOBILE:
- break; // We will handle sub-types after the switch.
- default:
- Log.w(LOGTAG, "Ignoring the current network type.");
- return NetworkType.NETWORK_UNKNOWN;
- }
-
- TelephonyManager tm =
- (TelephonyManager)sInstance.mApplicationContext.getSystemService(Context.TELEPHONY_SERVICE);
- if (tm == null) {
- Log.e(LOGTAG, "Telephony service does not exist");
- return NetworkType.NETWORK_UNKNOWN;
- }
-
- switch (tm.getNetworkType()) {
- case TelephonyManager.NETWORK_TYPE_IDEN:
- case TelephonyManager.NETWORK_TYPE_CDMA:
- return NetworkType.NETWORK_2_G;
- case TelephonyManager.NETWORK_TYPE_GPRS:
- case TelephonyManager.NETWORK_TYPE_1xRTT:
- return NetworkType.NETWORK_2_5_G;
- case TelephonyManager.NETWORK_TYPE_EDGE:
- return NetworkType.NETWORK_2_75_G;
- case TelephonyManager.NETWORK_TYPE_UMTS:
- case TelephonyManager.NETWORK_TYPE_EVDO_0:
- return NetworkType.NETWORK_3_G;
- case TelephonyManager.NETWORK_TYPE_HSPA:
- case TelephonyManager.NETWORK_TYPE_HSDPA:
- case TelephonyManager.NETWORK_TYPE_HSUPA:
- case TelephonyManager.NETWORK_TYPE_EVDO_A:
- case TelephonyManager.NETWORK_TYPE_EVDO_B:
- case TelephonyManager.NETWORK_TYPE_EHRPD:
- return NetworkType.NETWORK_3_5_G;
- case TelephonyManager.NETWORK_TYPE_HSPAP:
- return NetworkType.NETWORK_3_75_G;
- case TelephonyManager.NETWORK_TYPE_LTE:
- return NetworkType.NETWORK_3_9_G;
- case TelephonyManager.NETWORK_TYPE_UNKNOWN:
- default:
- Log.w(LOGTAG, "Connected to an unknown mobile network!");
- return NetworkType.NETWORK_UNKNOWN;
- }
- }
-
- private static double getNetworkSpeed(NetworkType aType) {
- switch (aType) {
- case NETWORK_NONE:
- return 0.0;
- case NETWORK_ETHERNET:
- return kNetworkSpeedEthernet;
- case NETWORK_WIFI:
- return kNetworkSpeedWifi;
- case NETWORK_WIMAX:
- return kNetworkSpeedWiMax;
- case NETWORK_2_G:
- return kNetworkSpeed_2_G;
- case NETWORK_2_5_G:
- return kNetworkSpeed_2_5_G;
- case NETWORK_2_75_G:
- return kNetworkSpeed_2_75_G;
- case NETWORK_3_G:
- return kNetworkSpeed_3_G;
- case NETWORK_3_5_G:
- return kNetworkSpeed_3_5_G;
- case NETWORK_3_75_G:
- return kNetworkSpeed_3_75_G;
- case NETWORK_3_9_G:
- return kNetworkSpeed_3_9_G;
- case NETWORK_UNKNOWN:
- default:
- return kDefaultBandwidth;
- }
- }
-
- private static boolean isNetworkUsuallyMetered(NetworkType aType) {
- switch (aType) {
- case NETWORK_NONE:
- case NETWORK_UNKNOWN:
- case NETWORK_ETHERNET:
- case NETWORK_WIFI:
- case NETWORK_WIMAX:
- return false;
- case NETWORK_2_G:
- case NETWORK_2_5_G:
- case NETWORK_2_75_G:
- case NETWORK_3_G:
- case NETWORK_3_5_G:
- case NETWORK_3_75_G:
- case NETWORK_3_9_G:
- return true;
- default:
- Log.e(LOGTAG, "Got an unexpected network type!");
- return false;
- }
- }
-}
diff --git a/mobile/android/base/GeckoPreferenceFragment.java b/mobile/android/base/GeckoPreferenceFragment.java
deleted file mode 100644
index 8545618ec..000000000
--- a/mobile/android/base/GeckoPreferenceFragment.java
+++ /dev/null
@@ -1,45 +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.gecko;
-
-import android.preference.Preference;
-import android.preference.PreferenceCategory;
-import android.preference.PreferenceFragment;
-import android.preference.PreferenceScreen;
-import android.os.Bundle;
-import android.util.Log;
-
-/* A simple implementation of PreferenceFragment for large screen devices
- * This will strip category headers (so that they aren't shown to the user twice)
- * as well as initializing Gecko prefs when a fragment is shown.
-*/
-public class GeckoPreferenceFragment extends PreferenceFragment {
-
- private static final String LOGTAG = "GeckoPreferenceFragment";
- private int mPrefsRequestId = 0;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- String resource = getArguments().getString("resource");
- int res = getActivity().getResources().getIdentifier(resource,
- "xml",
- getActivity().getPackageName());
- addPreferencesFromResource(res);
-
- PreferenceScreen screen = getPreferenceScreen();
- setPreferenceScreen(screen);
- mPrefsRequestId = ((GeckoPreferences)getActivity()).setupPreferences(screen);
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- if (mPrefsRequestId > 0) {
- PrefsHelper.removeObserver(mPrefsRequestId);
- }
- }
-}
diff --git a/mobile/android/base/GeckoPreferences.java b/mobile/android/base/GeckoPreferences.java
deleted file mode 100644
index 0986be50c..000000000
--- a/mobile/android/base/GeckoPreferences.java
+++ /dev/null
@@ -1,729 +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.gecko;
-
-import org.mozilla.gecko.background.common.GlobalConstants;
-import org.mozilla.gecko.background.healthreport.HealthReportConstants;
-import org.mozilla.gecko.util.GeckoEventListener;
-import org.mozilla.gecko.GeckoPreferenceFragment;
-import org.mozilla.gecko.util.ThreadUtils;
-
-import org.json.JSONArray;
-import org.json.JSONObject;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.Fragment;
-import android.app.NotificationManager;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.os.Build;
-import android.os.Bundle;
-import android.preference.CheckBoxPreference;
-import android.preference.EditTextPreference;
-import android.preference.ListPreference;
-import android.preference.Preference;
-import android.preference.Preference.OnPreferenceChangeListener;
-import android.preference.PreferenceActivity;
-import android.preference.PreferenceGroup;
-import android.preference.PreferenceManager;
-import android.preference.PreferenceScreen;
-import android.preference.TwoStatePreference;
-import android.text.Editable;
-import android.text.InputType;
-import android.text.TextUtils;
-import android.text.TextWatcher;
-import android.util.Log;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-import android.widget.Toast;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class GeckoPreferences
- extends PreferenceActivity
- implements OnPreferenceChangeListener, GeckoEventListener, GeckoActivityStatus
-{
- private static final String LOGTAG = "GeckoPreferences";
-
- private static final String NON_PREF_PREFIX = "android.not_a_preference.";
- public static final String INTENT_EXTRA_RESOURCES = "resource";
- public static String PREFS_HEALTHREPORT_UPLOAD_ENABLED = NON_PREF_PREFIX + "healthreport.uploadEnabled";
-
- private static boolean sIsCharEncodingEnabled = false;
- private boolean mInitialized = false;
- private int mPrefsRequestId = 0;
-
- // These match keys in resources/xml/preferences.xml.in.
- private static String PREFS_DATA_REPORTING_PREFERENCES = NON_PREF_PREFIX + "datareporting.preferences";
- private static String PREFS_TELEMETRY_ENABLED = "datareporting.telemetry.enabled";
- private static String PREFS_MENU_CHAR_ENCODING = "browser.menu.showCharacterEncoding";
- private static String PREFS_MP_ENABLED = "privacy.masterpassword.enabled";
- private static String PREFS_UPDATER_AUTODOWNLOAD = "app.update.autodownload";
- private static String PREFS_HEALTHREPORT_LINK = NON_PREF_PREFIX + "healthreport.link";
-
- public static String PREFS_RESTORE_SESSION = NON_PREF_PREFIX + "restoreSession";
-
- // These values are chosen to be distinct from other Activity constants.
- private static int REQUEST_CODE_PREF_SCREEN = 5;
- private static int RESULT_CODE_EXIT_SETTINGS = 6;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- // For fragment-capable devices, display the default fragment if no explicit fragment to show.
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB &&
- !getIntent().hasExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT)) {
- setupTopLevelFragmentIntent();
- }
-
- super.onCreate(savedInstanceState);
-
- // Use setResourceToOpen to specify these extras.
- Bundle intentExtras = getIntent().getExtras();
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
- if (intentExtras != null && intentExtras.containsKey(INTENT_EXTRA_RESOURCES)) {
- String resourceName = intentExtras.getString(INTENT_EXTRA_RESOURCES);
- int resource = getResources().getIdentifier(resourceName, "xml", getPackageName());
- addPreferencesFromResource(resource);
- } else {
- addPreferencesFromResource(R.xml.preferences);
- }
- }
-
- registerEventListener("Sanitize:Finished");
-
- if (Build.VERSION.SDK_INT >= 14)
- getActionBar().setHomeButtonEnabled(true);
-
- // If launched from notification, explicitly cancel the notification.
- if (intentExtras != null && intentExtras.containsKey(DataReportingNotification.ALERT_NAME_DATAREPORTING_NOTIFICATION)) {
- NotificationManager notificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
- notificationManager.cancel(DataReportingNotification.ALERT_NAME_DATAREPORTING_NOTIFICATION.hashCode());
- }
- }
-
- /**
- * Set intent to display top-level settings fragment.
- */
- private void setupTopLevelFragmentIntent() {
- Intent intent = getIntent();
- // Check intent to determine settings screen to display.
- Bundle intentExtras = intent.getExtras();
- Bundle fragmentArgs = new Bundle();
- // Add resource argument to fragment if it exists.
- if (intentExtras != null && intentExtras.containsKey(INTENT_EXTRA_RESOURCES)) {
- String resource = intentExtras.getString(INTENT_EXTRA_RESOURCES);
- fragmentArgs.putString(INTENT_EXTRA_RESOURCES, resource);
- } else {
- // Use top-level settings screen.
- if (!onIsMultiPane()) {
- fragmentArgs.putString(INTENT_EXTRA_RESOURCES, "preferences");
- } else {
- fragmentArgs.putString(INTENT_EXTRA_RESOURCES, "preferences_general");
- }
- }
-
- // Build fragment intent.
- intent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT, GeckoPreferenceFragment.class.getName());
- intent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS, fragmentArgs);
- }
-
- @Override
- public void onBuildHeaders(List<Header> target) {
- if (onIsMultiPane())
- loadHeadersFromResource(R.xml.preference_headers, target);
- }
-
- @Override
- public void onWindowFocusChanged(boolean hasFocus) {
- if (!hasFocus || mInitialized)
- return;
-
- mInitialized = true;
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
- PreferenceScreen screen = getPreferenceScreen();
- mPrefsRequestId = setupPreferences(screen);
- }
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- unregisterEventListener("Sanitize:Finished");
- if (mPrefsRequestId > 0) {
- PrefsHelper.removeObserver(mPrefsRequestId);
- }
- }
-
- @Override
- public void onPause() {
- super.onPause();
-
- if (getApplication() instanceof GeckoApplication) {
- ((GeckoApplication) getApplication()).onActivityPause(this);
- }
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- if (getApplication() instanceof GeckoApplication) {
- ((GeckoApplication) getApplication()).onActivityResume(this);
- }
- }
-
- @Override
- public void startActivity(Intent intent) {
- // For settings, we want to be able to pass results up the chain
- // of preference screens so Settings can behave as a single unit.
- // Specifically, when we open a link, we want to back out of all
- // the settings screens.
- // We need to start nested PreferenceScreens withStartActivityForResult().
- // Android doesn't let us do that (see Preference.onClick), so we're overriding here.
- startActivityForResult(intent, REQUEST_CODE_PREF_SCREEN);
- }
-
- @Override
- public void startWithFragment(String fragmentName, Bundle args,
- Fragment resultTo, int resultRequestCode, int titleRes, int shortTitleRes) {
- // Overriding because we want to use startActivityForResult for Fragment intents.
- Intent intent = onBuildStartFragmentIntent(fragmentName, args, titleRes, shortTitleRes);
- if (resultTo == null) {
- startActivityForResult(intent, REQUEST_CODE_PREF_SCREEN);
- } else {
- resultTo.startActivityForResult(intent, resultRequestCode);
- }
- }
-
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (REQUEST_CODE_PREF_SCREEN == requestCode && RESULT_CODE_EXIT_SETTINGS == resultCode) {
- // Pass this result up to the parent activity.
- setResult(RESULT_CODE_EXIT_SETTINGS);
- finish();
- }
- }
-
- @Override
- public void handleMessage(String event, JSONObject message) {
- try {
- if (event.equals("Sanitize:Finished")) {
- boolean success = message.getBoolean("success");
- final int stringRes = success ? R.string.private_data_success : R.string.private_data_fail;
- final Context context = this;
- ThreadUtils.postToUiThread(new Runnable () {
- @Override
- public void run() {
- Toast.makeText(context, stringRes, Toast.LENGTH_SHORT).show();
- }
- });
- }
- } catch (Exception e) {
- Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
- }
- }
-
- /**
- * Initialize all of the preferences (native of Gecko ones) for this screen.
- *
- * @param prefs The android.preference.PreferenceGroup to initialize
- * @return The integer id for the PrefsHelper.PrefHandlerBase listener added
- * to monitor changes to Gecko prefs.
- */
- public int setupPreferences(PreferenceGroup prefs) {
- ArrayList<String> list = new ArrayList<String>();
- setupPreferences(prefs, list);
- return getGeckoPreferences(prefs, list);
- }
-
- /**
- * Recursively loop through a PreferenceGroup. Initialize native Android prefs,
- * and build a list of Gecko preferences in the passed in prefs array
- *
- * @param preferences The android.preference.PreferenceGroup to initialize
- * @param prefs An ArrayList to fill with Gecko preferences that need to be
- * initialized
- * @return The integer id for the PrefsHelper.PrefHandlerBase listener added
- * to monitor changes to Gecko prefs.
- */
- private void setupPreferences(PreferenceGroup preferences, ArrayList<String> prefs) {
- for (int i = 0; i < preferences.getPreferenceCount(); i++) {
- Preference pref = preferences.getPreference(i);
- String key = pref.getKey();
- if (pref instanceof PreferenceGroup) {
- // If no datareporting is enabled, remove UI.
- if (PREFS_DATA_REPORTING_PREFERENCES.equals(key)) {
- if (!AppConstants.MOZ_DATA_REPORTING) {
- preferences.removePreference(pref);
- i--;
- continue;
- }
- }
- setupPreferences((PreferenceGroup) pref, prefs);
- } else {
- pref.setOnPreferenceChangeListener(this);
- if (!AppConstants.MOZ_UPDATER &&
- PREFS_UPDATER_AUTODOWNLOAD.equals(key)) {
- preferences.removePreference(pref);
- i--;
- continue;
- } else if (!AppConstants.MOZ_TELEMETRY_REPORTING &&
- PREFS_TELEMETRY_ENABLED.equals(key)) {
- preferences.removePreference(pref);
- i--;
- continue;
- } else if (!AppConstants.MOZ_SERVICES_HEALTHREPORT &&
- (PREFS_HEALTHREPORT_UPLOAD_ENABLED.equals(key) ||
- PREFS_HEALTHREPORT_LINK.equals(key))) {
- preferences.removePreference(pref);
- i--;
- continue;
- }
-
- // Some Preference UI elements are not actually preferences,
- // but they require a key to work correctly. For example,
- // "Clear private data" requires a key for its state to be
- // saved when the orientation changes. It uses the
- // "android.not_a_preference.privacy.clear" key - which doesn't
- // exist in Gecko - to satisfy this requirement.
- if (key != null && !key.startsWith(NON_PREF_PREFIX)) {
- prefs.add(key);
- }
- }
- }
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- finish();
- return true;
- }
-
- return super.onOptionsItemSelected(item);
- }
-
- final private int DIALOG_CREATE_MASTER_PASSWORD = 0;
- final private int DIALOG_REMOVE_MASTER_PASSWORD = 1;
-
- public static void setCharEncodingState(boolean enabled) {
- sIsCharEncodingEnabled = enabled;
- }
-
- public static boolean getCharEncodingState() {
- return sIsCharEncodingEnabled;
- }
-
- /**
- * Broadcast an intent with <code>pref</code>, <code>branch</code>, and
- * <code>enabled</code> extras. This is intended to represent the
- * notification of a preference value to observers.
- *
- * The broadcast will be sent only to receivers registered with the
- * (Fennec-specific) per-Android package permission.
- */
- public static void broadcastPrefAction(final Context context,
- final String action,
- final String pref,
- final boolean value) {
- final Intent intent = new Intent(action);
- intent.setAction(action);
- intent.putExtra("pref", pref);
- intent.putExtra("branch", GeckoApp.PREFS_NAME);
- intent.putExtra("enabled", value);
-
- // There is a race here, but GeckoProfile returns the default profile
- // when Gecko is not explicitly running for a different profile. In a
- // multi-profile world, this will need to be updated (possibly to
- // broadcast settings for all profiles). See Bug 882182.
- GeckoProfile profile = GeckoProfile.get(context);
- if (profile != null) {
- intent.putExtra("profileName", profile.getName());
- intent.putExtra("profilePath", profile.getDir().getAbsolutePath());
- }
-
- Log.d(LOGTAG, "Broadcast: " + action + ", " + pref + ", " + GeckoApp.PREFS_NAME + ", " + value);
- context.sendBroadcast(intent, GlobalConstants.PER_ANDROID_PACKAGE_PERMISSION);
- }
-
- /**
- * Broadcast the provided value as the value of the
- * <code>PREFS_HEALTHREPORT_UPLOAD_ENABLED</code> pref.
- */
- public static void broadcastHealthReportUploadPref(final Context context, final boolean value) {
- broadcastPrefAction(context,
- HealthReportConstants.ACTION_HEALTHREPORT_UPLOAD_PREF,
- PREFS_HEALTHREPORT_UPLOAD_ENABLED,
- value);
- }
-
- /**
- * Broadcast the current value of the
- * <code>PREFS_HEALTHREPORT_UPLOAD_ENABLED</code> pref.
- */
- public static void broadcastHealthReportUploadPref(final Context context) {
- final boolean value = getBooleanPref(context, PREFS_HEALTHREPORT_UPLOAD_ENABLED, true);
- broadcastHealthReportUploadPref(context, value);
- }
-
- /**
- * Return the value of the named preference in the default preferences file.
- *
- * This corresponds to the storage that backs preferences.xml.
- * @param context a <code>Context</code>; the
- * <code>PreferenceActivity</code> will suffice, but this
- * method is intended to be called from other contexts
- * within the application, not just this <code>Activity</code>.
- * @param name the name of the preference to retrieve.
- * @param def the default value to return if the preference is not present.
- * @return the value of the preference, or the default.
- */
- public static boolean getBooleanPref(final Context context, final String name, boolean def) {
- final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
- return prefs.getBoolean(name, def);
- }
-
- @Override
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- String prefName = preference.getKey();
- if (PREFS_MP_ENABLED.equals(prefName)) {
- showDialog((Boolean) newValue ? DIALOG_CREATE_MASTER_PASSWORD : DIALOG_REMOVE_MASTER_PASSWORD);
- return false;
- } else if (PREFS_MENU_CHAR_ENCODING.equals(prefName)) {
- setCharEncodingState(((String) newValue).equals("true"));
- } else if (PREFS_UPDATER_AUTODOWNLOAD.equals(prefName)) {
- org.mozilla.gecko.updater.UpdateServiceHelper.registerForUpdates(GeckoAppShell.getContext(), (String) newValue);
- } else if (PREFS_HEALTHREPORT_UPLOAD_ENABLED.equals(prefName)) {
- // The healthreport pref only lives in Android, so we do not persist
- // to Gecko, but we do broadcast intent to the health report
- // background uploader service, which will start or stop the
- // repeated background upload attempts.
- broadcastHealthReportUploadPref(GeckoAppShell.getContext(), ((Boolean) newValue).booleanValue());
- return true;
- } else if (PREFS_RESTORE_SESSION.equals(prefName)) {
- // Do nothing; this pref will be read at startup.
- return true;
- }
-
- if (!TextUtils.isEmpty(prefName)) {
- PrefsHelper.setPref(prefName, newValue);
- }
- if (preference instanceof ListPreference) {
- // We need to find the entry for the new value
- int newIndex = ((ListPreference) preference).findIndexOfValue((String) newValue);
- CharSequence newEntry = ((ListPreference) preference).getEntries()[newIndex];
- ((ListPreference) preference).setSummary(newEntry);
- } else if (preference instanceof LinkPreference) {
- setResult(RESULT_CODE_EXIT_SETTINGS);
- finish();
- } else if (preference instanceof FontSizePreference) {
- final FontSizePreference fontSizePref = (FontSizePreference) preference;
- fontSizePref.setSummary(fontSizePref.getSavedFontSizeName());
- }
- return true;
- }
-
- private EditText getTextBox(int aHintText) {
- EditText input = new EditText(GeckoAppShell.getContext());
- int inputtype = InputType.TYPE_CLASS_TEXT;
- inputtype |= InputType.TYPE_TEXT_VARIATION_PASSWORD | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
- input.setInputType(inputtype);
-
- String hint = getResources().getString(aHintText);
- input.setHint(aHintText);
- return input;
- }
-
- private class PasswordTextWatcher implements TextWatcher {
- EditText input1 = null;
- EditText input2 = null;
- AlertDialog dialog = null;
-
- PasswordTextWatcher(EditText aInput1, EditText aInput2, AlertDialog aDialog) {
- input1 = aInput1;
- input2 = aInput2;
- dialog = aDialog;
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- if (dialog == null)
- return;
-
- String text1 = input1.getText().toString();
- String text2 = input2.getText().toString();
- boolean disabled = TextUtils.isEmpty(text1) || TextUtils.isEmpty(text2) || !text1.equals(text2);
- dialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(!disabled);
- }
-
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) { }
- }
-
- private class EmptyTextWatcher implements TextWatcher {
- EditText input = null;
- AlertDialog dialog = null;
-
- EmptyTextWatcher(EditText aInput, AlertDialog aDialog) {
- input = aInput;
- dialog = aDialog;
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- if (dialog == null)
- return;
-
- String text = input.getText().toString();
- boolean disabled = TextUtils.isEmpty(text);
- dialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(!disabled);
- }
-
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) { }
- }
-
- @Override
- protected Dialog onCreateDialog(int id) {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- LinearLayout linearLayout = new LinearLayout(this);
- linearLayout.setOrientation(LinearLayout.VERTICAL);
- AlertDialog dialog = null;
- switch(id) {
- case DIALOG_CREATE_MASTER_PASSWORD:
- final EditText input1 = getTextBox(R.string.masterpassword_password);
- final EditText input2 = getTextBox(R.string.masterpassword_confirm);
- linearLayout.addView(input1);
- linearLayout.addView(input2);
-
- builder.setTitle(R.string.masterpassword_create_title)
- .setView((View) linearLayout)
- .setPositiveButton(R.string.button_ok, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- JSONObject jsonPref = new JSONObject();
- try {
- jsonPref.put("name", PREFS_MP_ENABLED);
- jsonPref.put("type", "string");
- jsonPref.put("value", input1.getText().toString());
-
- GeckoEvent event = GeckoEvent.createBroadcastEvent("Preferences:Set", jsonPref.toString());
- GeckoAppShell.sendEventToGecko(event);
- } catch(Exception ex) {
- Log.e(LOGTAG, "Error setting master password", ex);
- }
- return;
- }
- })
- .setNegativeButton(R.string.button_cancel, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- return;
- }
- });
- dialog = builder.create();
- dialog.setOnShowListener(new DialogInterface.OnShowListener() {
- @Override
- public void onShow(DialogInterface dialog) {
- input1.setText("");
- input2.setText("");
- input1.requestFocus();
- }
- });
-
- PasswordTextWatcher watcher = new PasswordTextWatcher(input1, input2, dialog);
- input1.addTextChangedListener((TextWatcher) watcher);
- input2.addTextChangedListener((TextWatcher) watcher);
-
- break;
- case DIALOG_REMOVE_MASTER_PASSWORD:
- final EditText input = getTextBox(R.string.masterpassword_password);
- linearLayout.addView(input);
-
- builder.setTitle(R.string.masterpassword_remove_title)
- .setView((View) linearLayout)
- .setPositiveButton(R.string.button_ok, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- PrefsHelper.setPref(PREFS_MP_ENABLED, input.getText().toString());
- }
- })
- .setNegativeButton(R.string.button_cancel, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- return;
- }
- });
- dialog = builder.create();
- dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
- @Override
- public void onDismiss(DialogInterface dialog) {
- input.setText("");
- }
- });
- dialog.setOnShowListener(new DialogInterface.OnShowListener() {
- @Override
- public void onShow(DialogInterface dialog) {
- input.setText("");
- }
- });
- input.addTextChangedListener(new EmptyTextWatcher(input, dialog));
- break;
- default:
- return null;
- }
-
- return dialog;
- }
-
- // Initialize preferences by requesting the preference values from Gecko
- private int getGeckoPreferences(final PreferenceGroup screen, ArrayList<String> prefs) {
- JSONArray jsonPrefs = new JSONArray(prefs);
-
- return PrefsHelper.getPrefs(jsonPrefs, new PrefsHelper.PrefHandlerBase() {
- private Preference getField(String prefName) {
- return screen.findPreference(prefName);
- }
-
- // Handle v14 TwoStatePreference with backwards compatibility.
- class CheckBoxPrefSetter {
- public void setBooleanPref(Preference preference, boolean value) {
- if ((preference instanceof CheckBoxPreference) &&
- ((CheckBoxPreference) preference).isChecked() != value) {
- ((CheckBoxPreference) preference).setChecked(value);
- }
- }
- }
-
- class TwoStatePrefSetter extends CheckBoxPrefSetter {
- @Override
- public void setBooleanPref(Preference preference, boolean value) {
- if ((preference instanceof TwoStatePreference) &&
- ((TwoStatePreference) preference).isChecked() != value) {
- ((TwoStatePreference) preference).setChecked(value);
- }
- }
- }
-
- @Override
- public void prefValue(String prefName, final boolean value) {
- final Preference pref = getField(prefName);
- final CheckBoxPrefSetter prefSetter;
- if (Build.VERSION.SDK_INT < 14) {
- prefSetter = new CheckBoxPrefSetter();
- } else {
- prefSetter = new TwoStatePrefSetter();
- }
- ThreadUtils.postToUiThread(new Runnable() {
- public void run() {
- prefSetter.setBooleanPref(pref, value);
- }
- });
- }
-
- @Override
- public void prefValue(String prefName, final String value) {
- final Preference pref = getField(prefName);
- if (pref instanceof EditTextPreference) {
- ThreadUtils.postToUiThread(new Runnable() {
- @Override
- public void run() {
- ((EditTextPreference) pref).setText(value);
- }
- });
- } else if (pref instanceof ListPreference) {
- ThreadUtils.postToUiThread(new Runnable() {
- @Override
- public void run() {
- ((ListPreference) pref).setValue(value);
- // Set the summary string to the current entry
- CharSequence selectedEntry = ((ListPreference) pref).getEntry();
- ((ListPreference) pref).setSummary(selectedEntry);
- }
- });
- } else if (pref instanceof FontSizePreference) {
- final FontSizePreference fontSizePref = (FontSizePreference) pref;
- fontSizePref.setSavedFontSize(value);
- final String fontSizeName = fontSizePref.getSavedFontSizeName();
- ThreadUtils.postToUiThread(new Runnable() {
- @Override
- public void run() {
- fontSizePref.setSummary(fontSizeName); // Ex: "Small".
- }
- });
- }
- }
-
- @Override
- public boolean isObserver() {
- return true;
- }
-
- @Override
- public void finish() {
- // enable all preferences once we have them from gecko
- ThreadUtils.postToUiThread(new Runnable() {
- @Override
- public void run() {
- screen.setEnabled(true);
- }
- });
- }
- });
- }
-
- private void registerEventListener(String event) {
- GeckoAppShell.getEventDispatcher().registerEventListener(event, this);
- }
-
- private void unregisterEventListener(String event) {
- GeckoAppShell.getEventDispatcher().unregisterEventListener(event, this);
- }
-
- @Override
- public boolean isGeckoActivityOpened() {
- return false;
- }
-
- /**
- * Given an Intent instance, add extras to specify which settings section to
- * open.
- *
- * resource should be a valid Android XML resource identifier.
- *
- * The mechanism to open a section differs based on Android version.
- */
- public static void setResourceToOpen(final Intent intent, final String resource) {
- if (intent == null) {
- throw new IllegalArgumentException("intent must not be null");
- }
- if (resource == null) {
- return;
- }
-
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
- intent.putExtra("resource", resource);
- } else {
- intent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT, GeckoPreferenceFragment.class.getName());
-
- Bundle fragmentArgs = new Bundle();
- fragmentArgs.putString("resource", resource);
- intent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS, fragmentArgs);
- }
- }
-}
diff --git a/mobile/android/base/GeckoProfile.java b/mobile/android/base/GeckoProfile.java
deleted file mode 100644
index f40264c6f..000000000
--- a/mobile/android/base/GeckoProfile.java
+++ /dev/null
@@ -1,399 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; 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.gecko;
-
-import org.mozilla.gecko.util.INIParser;
-import org.mozilla.gecko.util.INISection;
-
-import android.content.Context;
-import android.text.TextUtils;
-import android.util.Log;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.nio.charset.Charset;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Hashtable;
-
-public final class GeckoProfile {
- private static final String LOGTAG = "GeckoProfile";
-
- private static HashMap<String, GeckoProfile> sProfileCache = new HashMap<String, GeckoProfile>();
- private static String sDefaultProfileName = null;
-
- private final Context mContext;
- private final String mName;
- private File mMozDir;
- private File mDir;
-
- static private INIParser getProfilesINI(Context context) {
- File filesDir = context.getFilesDir();
- File mozillaDir = new File(filesDir, "mozilla");
- File profilesIni = new File(mozillaDir, "profiles.ini");
- return new INIParser(profilesIni);
- }
-
- public static GeckoProfile get(Context context) {
- if (context instanceof GeckoApp)
- return get(context, ((GeckoApp)context).getDefaultProfileName());
-
- return get(context, "");
- }
-
- public static GeckoProfile get(Context context, String profileName) {
- synchronized (sProfileCache) {
- GeckoProfile profile = sProfileCache.get(profileName);
- if (profile != null)
- return profile;
- }
- return get(context, profileName, null);
- }
-
- public static GeckoProfile get(Context context, String profileName, String profilePath) {
- if (context == null) {
- throw new IllegalArgumentException("context must be non-null");
- }
-
- // if no profile was passed in, look for the default profile listed in profiles.ini
- // if that doesn't exist, look for a profile called 'default'
- if (TextUtils.isEmpty(profileName) && TextUtils.isEmpty(profilePath)) {
- profileName = GeckoProfile.findDefaultProfile(context);
- if (profileName == null)
- profileName = "default";
- }
-
- // actually try to look up the profile
- synchronized (sProfileCache) {
- GeckoProfile profile = sProfileCache.get(profileName);
- if (profile == null) {
- profile = new GeckoProfile(context, profileName, profilePath);
- sProfileCache.put(profileName, profile);
- } else {
- profile.setDir(profilePath);
- }
- return profile;
- }
- }
-
- public static File ensureMozillaDirectory(Context context) throws IOException {
- synchronized (context) {
- File filesDir = context.getFilesDir();
- File mozDir = new File(filesDir, "mozilla");
- if (! mozDir.exists()) {
- if (! mozDir.mkdirs()) {
- throw new IOException("Unable to create mozilla directory at " + mozDir.getAbsolutePath());
- }
- }
- return mozDir;
- }
- }
-
- public static boolean removeProfile(Context context, String profileName) {
- return new GeckoProfile(context, profileName).remove();
- }
-
- private GeckoProfile(Context context, String profileName) {
- mContext = context;
- mName = profileName;
- }
-
- private GeckoProfile(Context context, String profileName, String profilePath) {
- mContext = context;
- mName = profileName;
- setDir(profilePath);
- }
-
- private void setDir(String profilePath) {
- if (!TextUtils.isEmpty(profilePath)) {
- File dir = new File(profilePath);
- if (dir.exists() && dir.isDirectory()) {
- mDir = dir;
- } else {
- Log.w(LOGTAG, "requested profile directory missing: " + profilePath);
- }
- }
- }
-
- public String getName() {
- return mName;
- }
-
- public synchronized File getDir() {
- if (mDir != null) {
- return mDir;
- }
-
- try {
- // Check for old profiles that may need migration.
- ProfileMigrator profileMigrator = new ProfileMigrator(mContext);
- if (!GeckoApp.sIsUsingCustomProfile &&
- !profileMigrator.isProfileMoved()) {
- Log.i(LOGTAG, "New installation or update, checking for old profiles.");
- profileMigrator.launchMoveProfile();
- }
-
- // now check if a profile with this name that already exists
- File mozillaDir = ensureMozillaDirectory(mContext);
- mDir = findProfileDir(mozillaDir);
- if (mDir == null) {
- // otherwise create it
- mDir = createProfileDir(mozillaDir);
- } else {
- Log.d(LOGTAG, "Found profile dir: " + mDir.getAbsolutePath());
- }
- } catch (IOException ioe) {
- Log.e(LOGTAG, "Error getting profile dir", ioe);
- }
- return mDir;
- }
-
- public File getFile(String aFile) {
- File f = getDir();
- if (f == null)
- return null;
-
- return new File(f, aFile);
- }
-
- public File getFilesDir() {
- return mContext.getFilesDir();
- }
-
- /**
- * Moves the session file to the backup session file.
- *
- * sessionstore.js should hold the current session, and sessionstore.bak
- * should hold the previous session (where it is used to read the "tabs
- * from last time"). Normally, sessionstore.js is moved to sessionstore.bak
- * on a clean quit, but this doesn't happen if Fennec crashed. Thus, this
- * method should be called after a crash so sessionstore.bak correctly
- * holds the previous session.
- */
- public void moveSessionFile() {
- File sessionFile = getFile("sessionstore.js");
- if (sessionFile != null && sessionFile.exists()) {
- File sessionFileBackup = getFile("sessionstore.bak");
- sessionFile.renameTo(sessionFileBackup);
- }
- }
-
- /**
- * Get the string from a session file.
- *
- * The session can either be read from sessionstore.js or sessionstore.bak.
- * In general, sessionstore.js holds the current session, and
- * sessionstore.bak holds the previous session.
- *
- * @param readBackup if true, the session is read from sessionstore.bak;
- * otherwise, the session is read from sessionstore.js
- *
- * @return the session string
- */
- public String readSessionFile(boolean readBackup) {
- File sessionFile = getFile(readBackup ? "sessionstore.bak" : "sessionstore.js");
-
- try {
- if (sessionFile != null && sessionFile.exists()) {
- return readFile(sessionFile);
- }
- } catch (IOException ioe) {
- Log.e(LOGTAG, "Unable to read session file", ioe);
- }
- return null;
- }
-
- public String readFile(String filename) throws IOException {
- File dir = getDir();
- if (dir == null) {
- throw new IOException("No profile directory found");
- }
- File target = new File(dir, filename);
- return readFile(target);
- }
-
- private String readFile(File target) throws IOException {
- FileReader fr = new FileReader(target);
- try {
- StringBuffer sb = new StringBuffer();
- char[] buf = new char[8192];
- int read = fr.read(buf);
- while (read >= 0) {
- sb.append(buf, 0, read);
- read = fr.read(buf);
- }
- return sb.toString();
- } finally {
- fr.close();
- }
- }
-
- private boolean remove() {
- try {
- File mozillaDir = ensureMozillaDirectory(mContext);
- mDir = findProfileDir(mozillaDir);
- if (mDir == null)
- return false;
-
- INIParser parser = getProfilesINI(mContext);
-
- Hashtable<String, INISection> sections = parser.getSections();
- for (Enumeration<INISection> e = sections.elements(); e.hasMoreElements();) {
- INISection section = e.nextElement();
- String name = section.getStringProperty("Name");
-
- if (name == null || !name.equals(mName))
- continue;
-
- if (section.getName().startsWith("Profile")) {
- // ok, we have stupid Profile#-named things. Rename backwards.
- try {
- int sectionNumber = Integer.parseInt(section.getName().substring("Profile".length()));
- String curSection = "Profile" + sectionNumber;
- String nextSection = "Profile" + (sectionNumber+1);
-
- sections.remove(curSection);
-
- while (sections.containsKey(nextSection)) {
- parser.renameSection(nextSection, curSection);
- sectionNumber++;
-
- curSection = nextSection;
- nextSection = "Profile" + (sectionNumber+1);
- }
- } catch (NumberFormatException nex) {
- // uhm, malformed Profile thing; we can't do much.
- Log.e(LOGTAG, "Malformed section name in profiles.ini: " + section.getName());
- return false;
- }
- } else {
- // this really shouldn't be the case, but handle it anyway
- parser.removeSection(mName);
- return true;
- }
- }
-
- parser.write();
- return true;
- } catch (IOException ex) {
- Log.w(LOGTAG, "Failed to remove profile " + mName + ":\n" + ex);
- return false;
- }
- }
-
- public static String findDefaultProfile(Context context) {
- // Have we read the default profile from the INI already?
- // Changing the default profile requires a restart, so we don't
- // need to worry about runtime changes.
- if (sDefaultProfileName != null) {
- return sDefaultProfileName;
- }
-
- // Open profiles.ini to find the correct path
- INIParser parser = getProfilesINI(context);
-
- for (Enumeration<INISection> e = parser.getSections().elements(); e.hasMoreElements();) {
- INISection section = e.nextElement();
- if (section.getIntProperty("Default") == 1) {
- sDefaultProfileName = section.getStringProperty("Name");
- return sDefaultProfileName;
- }
- }
-
- return null;
- }
-
- private File findProfileDir(File mozillaDir) {
- // Open profiles.ini to find the correct path
- INIParser parser = getProfilesINI(mContext);
-
- for (Enumeration<INISection> e = parser.getSections().elements(); e.hasMoreElements();) {
- INISection section = e.nextElement();
- String name = section.getStringProperty("Name");
- if (name != null && name.equals(mName)) {
- if (section.getIntProperty("IsRelative") == 1) {
- return new File(mozillaDir, section.getStringProperty("Path"));
- }
- return new File(section.getStringProperty("Path"));
- }
- }
-
- return null;
- }
-
- private static String saltProfileName(String name) {
- String allowedChars = "abcdefghijklmnopqrstuvwxyz0123456789";
- StringBuffer salt = new StringBuffer(16);
- for (int i = 0; i < 8; i++) {
- salt.append(allowedChars.charAt((int)(Math.random() * allowedChars.length())));
- }
- salt.append('.');
- salt.append(name);
- return salt.toString();
- }
-
- private File createProfileDir(File mozillaDir) throws IOException {
- INIParser parser = getProfilesINI(mContext);
-
- // Salt the name of our requested profile
- String saltedName = saltProfileName(mName);
- File profileDir = new File(mozillaDir, saltedName);
- while (profileDir.exists()) {
- saltedName = saltProfileName(mName);
- profileDir = new File(mozillaDir, saltedName);
- }
-
- // Attempt to create the salted profile dir
- if (! profileDir.mkdirs()) {
- throw new IOException("Unable to create profile at " + profileDir.getAbsolutePath());
- }
- Log.d(LOGTAG, "Created new profile dir at " + profileDir.getAbsolutePath());
-
- // Now update profiles.ini
- // If this is the first time its created, we also add a General section
- // look for the first profile number that isn't taken yet
- int profileNum = 0;
- while (parser.getSection("Profile" + profileNum) != null) {
- profileNum++;
- }
-
- INISection profileSection = new INISection("Profile" + profileNum);
- profileSection.setProperty("Name", mName);
- profileSection.setProperty("IsRelative", 1);
- profileSection.setProperty("Path", saltedName);
-
- if (parser.getSection("General") == null) {
- INISection generalSection = new INISection("General");
- generalSection.setProperty("StartWithLastProfile", 1);
- parser.addSection(generalSection);
-
- // only set as default if this is the first profile we're creating
- profileSection.setProperty("Default", 1);
- }
-
- parser.addSection(profileSection);
- parser.write();
-
- // Write out profile creation time, mirroring the logic in nsToolkitProfileService.
- try {
- FileOutputStream stream = new FileOutputStream(profileDir.getAbsolutePath() + File.separator + "times.json");
- OutputStreamWriter writer = new OutputStreamWriter(stream, Charset.forName("UTF-8"));
- try {
- writer.append("{\"created\": " + System.currentTimeMillis() + "}\n");
- } finally {
- writer.close();
- }
- } catch (Exception e) {
- // Best-effort.
- Log.w(LOGTAG, "Couldn't write times.json.", e);
- }
-
- return profileDir;
- }
-}
diff --git a/mobile/android/base/GeckoScreenOrientationListener.java b/mobile/android/base/GeckoScreenOrientationListener.java
deleted file mode 100644
index e4ceecad3..000000000
--- a/mobile/android/base/GeckoScreenOrientationListener.java
+++ /dev/null
@@ -1,215 +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/. */
-
-package org.mozilla.gecko;
-
-import android.content.Context;
-import android.content.pm.ActivityInfo;
-import android.util.Log;
-import android.view.OrientationEventListener;
-import android.view.Surface;
-
-import java.util.Arrays;
-import java.util.List;
-
-import android.app.Activity;
-
-public class GeckoScreenOrientationListener {
- private static final String LOGTAG = "GeckoScreenOrientationListener";
-
- static class OrientationEventListenerImpl extends OrientationEventListener {
- public OrientationEventListenerImpl(Context c) {
- super(c);
- }
-
- @Override
- public void onOrientationChanged(int aOrientation) {
- GeckoScreenOrientationListener.getInstance().updateScreenOrientation();
- }
- }
-
- static private GeckoScreenOrientationListener sInstance = null;
-
- // Make sure that any change in dom/base/ScreenOrientation.h happens here too.
- static public final short eScreenOrientation_None = 0;
- static public final short eScreenOrientation_PortraitPrimary = 1; // PR_BIT(0)
- static public final short eScreenOrientation_PortraitSecondary = 2; // PR_BIT(1)
- static public final short eScreenOrientation_LandscapePrimary = 4; // PR_BIT(2)
- static public final short eScreenOrientation_LandscapeSecondary = 8; // PR_BIT(3)
-
- static private final short DEFAULT_ORIENTATION = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-
- private short mOrientation;
- private OrientationEventListenerImpl mListener = null;
-
- // Whether the listener should be listening to changes.
- private boolean mShouldBeListening = false;
- // Whether the listener should notify Gecko that a change happened.
- private boolean mShouldNotify = false;
- // The default orientation to use if nothing is specified
- private short mDefaultOrientation;
-
- private static final String DEFAULT_ORIENTATION_PREF = "app.orientation.default";
-
- private GeckoScreenOrientationListener() {
- mListener = new OrientationEventListenerImpl(GeckoAppShell.getContext());
-
- PrefsHelper.getPref(DEFAULT_ORIENTATION_PREF, new PrefsHelper.PrefHandlerBase() {
- @Override public void prefValue(String pref, String value) {
- mDefaultOrientation = orientationFromStringArray(value);
- unlockScreenOrientation();
- }
- });
-
- mDefaultOrientation = DEFAULT_ORIENTATION;
- }
-
- public static GeckoScreenOrientationListener getInstance() {
- if (sInstance == null) {
- sInstance = new GeckoScreenOrientationListener();
- }
-
- return sInstance;
- }
-
- public void start() {
- mShouldBeListening = true;
- updateScreenOrientation();
-
- if (mShouldNotify) {
- startListening();
- }
- }
-
- public void stop() {
- mShouldBeListening = false;
-
- if (mShouldNotify) {
- stopListening();
- }
- }
-
- public void enableNotifications() {
- updateScreenOrientation();
- mShouldNotify = true;
-
- if (mShouldBeListening) {
- startListening();
- }
- }
-
- public void disableNotifications() {
- mShouldNotify = false;
-
- if (mShouldBeListening) {
- stopListening();
- }
- }
-
- private void startListening() {
- mListener.enable();
- }
-
- private void stopListening() {
- mListener.disable();
- }
-
- private short orientationFromStringArray(String val) {
- List<String> orientations = Arrays.asList(val.split(","));
- // if nothing is listed, return unspecified
- if (orientations.size() == 0)
- return DEFAULT_ORIENTATION;
-
- // we dont' support multiple orientations yet. To avoid developer confusion,
- // just take the first one listed
- return orientationFromString(orientations.get(0));
- }
-
- private short orientationFromString(String val) {
- if ("portrait".equals(val))
- return (short)ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
- else if ("landscape".equals(val))
- return (short)ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
- else if ("portrait-primary".equals(val))
- return (short)ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
- else if ("portrait-secondary".equals(val))
- return (short)ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
- else if ("landscape-primary".equals(val))
- return (short)ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
- else if ("landscape-secondary".equals(val))
- return (short)ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
- return DEFAULT_ORIENTATION;
- }
-
- private void updateScreenOrientation() {
- Context context = GeckoAppShell.getContext();
- int rotation = mDefaultOrientation;
- if (context instanceof Activity) {
- rotation = ((Activity)context).getWindowManager().getDefaultDisplay().getRotation();
- }
- short previousOrientation = mOrientation;
-
- if (rotation == Surface.ROTATION_0) {
- mOrientation = eScreenOrientation_PortraitPrimary;
- } else if (rotation == Surface.ROTATION_180) {
- mOrientation = eScreenOrientation_PortraitSecondary;
- } else if (rotation == Surface.ROTATION_270) {
- mOrientation = eScreenOrientation_LandscapeSecondary;
- } else if (rotation == Surface.ROTATION_90) {
- mOrientation = eScreenOrientation_LandscapePrimary;
- } else {
- Log.e(LOGTAG, "Unexpected value received! (" + rotation + ")");
- return;
- }
-
- if (mShouldNotify && mOrientation != previousOrientation) {
- GeckoAppShell.sendEventToGecko(GeckoEvent.createScreenOrientationEvent(mOrientation));
- }
- }
-
- public short getScreenOrientation() {
- return mOrientation;
- }
-
- public void lockScreenOrientation(int aOrientation) {
- int orientation = 0;
-
- switch (aOrientation) {
- case eScreenOrientation_PortraitPrimary:
- orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
- break;
- case eScreenOrientation_PortraitSecondary:
- orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
- break;
- case eScreenOrientation_PortraitPrimary | eScreenOrientation_PortraitSecondary:
- orientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
- break;
- case eScreenOrientation_LandscapePrimary:
- orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
- break;
- case eScreenOrientation_LandscapeSecondary:
- orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
- break;
- case eScreenOrientation_LandscapePrimary | eScreenOrientation_LandscapeSecondary:
- orientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
- break;
- default:
- Log.e(LOGTAG, "Unexpected value received! (" + aOrientation + ")");
- return;
- }
- if (GeckoAppShell.getContext() instanceof Activity)
- ((Activity)GeckoAppShell.getContext()).setRequestedOrientation(orientation);
- updateScreenOrientation();
- }
-
- public void unlockScreenOrientation() {
- if (!(GeckoAppShell.getContext() instanceof Activity))
- return;
- if (((Activity)GeckoAppShell.getContext()).getRequestedOrientation() == mDefaultOrientation)
- return;
-
- ((Activity)GeckoAppShell.getContext()).setRequestedOrientation(mDefaultOrientation);
- updateScreenOrientation();
- }
-}
diff --git a/mobile/android/base/GeckoSmsManager.java b/mobile/android/base/GeckoSmsManager.java
deleted file mode 100644
index 0ab9963ef..000000000
--- a/mobile/android/base/GeckoSmsManager.java
+++ /dev/null
@@ -1,996 +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.gecko;
-
-import android.app.Activity;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.database.Cursor;
-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 android.util.Log;
-
-import static android.telephony.SmsMessage.MessageClass;
-
-import java.util.ArrayList;
-
-/**
- * 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 = GeckoSmsManager.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("GeckoSmsManager", "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("GeckoSmsManager", "Trying to get an unknown Envelope!");
- return null;
- }
-
- Envelope envelope = mEnvelopes.get(aId);
- if (envelope == null) {
- Log.e("GeckoSmsManager", "Trying to get an empty Envelope!");
- }
-
- return envelope;
- }
-
- public void destroyEnvelope(int aId) {
- if (aId < 0 || mEnvelopes.size() <= aId) {
- Log.e("GeckoSmsManager", "Trying to destroy an unknown Envelope!");
- return;
- }
-
- if (mEnvelopes.set(aId, null) == null) {
- Log.e("GeckoSmsManager", "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);
- }
-
- @Override
- 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("GeckoSmsManager", "Trying to get an unknown list!");
- return null;
- }
-
- Cursor cursor = mCursors.get(aId);
- if (cursor == null) {
- Log.e("GeckoSmsManager", "Trying to get an empty list!");
- }
-
- return cursor;
- }
-
- public void remove(int aId) {
- if (aId < 0 || mCursors.size() <= aId) {
- Log.e("GeckoSmsManager", "Trying to destroy an unknown list!");
- return;
- }
-
- Cursor cursor = mCursors.set(aId, null);
- if (cursor == null) {
- Log.e("GeckoSmsManager", "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 GeckoSmsManager
- 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.gecko.SMS_SENT";
- public final static String ACTION_SMS_DELIVERED = "org.mozilla.gecko.SMS_DELIVERED";
-
- /*
- * Make sure that the following error codes are in sync with |ErrorType| in:
- * dom/mobilemessage/src/Types.h
- * The error code are owned by the DOM.
- */
- 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;
-
- 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/src/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/src/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/src/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 GeckoSmsManager() {
- SmsIOThread.getInstance().start();
- }
-
- @Override
- public void start() {
- IntentFilter smsFilter = new IntentFilter();
- smsFilter.addAction(GeckoSmsManager.ACTION_SMS_RECEIVED);
- smsFilter.addAction(GeckoSmsManager.ACTION_SMS_SENT);
- smsFilter.addAction(GeckoSmsManager.ACTION_SMS_DELIVERED);
-
- GeckoAppShell.getContext().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]);
-
- notifySmsReceived(msg.getDisplayOriginatingAddress(),
- msg.getDisplayMessageBody(),
- getGeckoMessageClass(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("GeckoSmsManager", "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("GeckoSmsManager", "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("GeckoSmsManager", "SMS part sending failed!");
- }
-
- if (envelope.arePartsRemaining(part)) {
- return;
- }
-
- if (envelope.isFailing(part)) {
- if (part == Envelope.SubParts.SENT_PART) {
- notifySmsSendFailed(envelope.getError(), bundle.getInt("requestId"));
- Log.i("GeckoSmsManager", "SMS sending failed!");
- } else {
- notifySmsDelivery(envelope.getMessageId(),
- kDeliveryStatusError,
- bundle.getString("number"),
- bundle.getString("message"),
- envelope.getMessageTimestamp());
- Log.i("GeckoSmsManager", "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);
-
- notifySmsSent(id, number, message, timestamp,
- bundle.getInt("requestId"));
-
- envelope.setMessageId(id);
- envelope.setMessageTimestamp(timestamp);
-
- Log.i("GeckoSmsManager", "SMS sending was successfull!");
- } else {
- notifySmsDelivery(envelope.getMessageId(),
- kDeliveryStatusSuccess,
- bundle.getString("number"),
- bundle.getString("message"),
- envelope.getMessageTimestamp());
- Log.i("GeckoSmsManager", "SMS successfully 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;
- }
- }
-
- @Override
- 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(GeckoAppShell.getContext(),
- PendingIntentUID.generate(), sentIntent,
- PendingIntent.FLAG_CANCEL_CURRENT);
-
- PendingIntent deliveredPendingIntent =
- PendingIntent.getBroadcast(GeckoAppShell.getContext(),
- 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(GeckoAppShell.getContext(),
- PendingIntentUID.generate(), sentIntent,
- PendingIntent.FLAG_CANCEL_CURRENT)
- );
-
- deliveredPendingIntents.add(
- PendingIntent.getBroadcast(GeckoAppShell.getContext(),
- PendingIntentUID.generate(), deliveredIntent,
- PendingIntent.FLAG_CANCEL_CURRENT)
- );
- }
-
- sm.sendMultipartTextMessage(aNumber, "", parts, sentPendingIntents,
- deliveredPendingIntents);
- }
- } catch (Exception e) {
- Log.e("GeckoSmsManager", "Failed to send an SMS: ", e);
-
- if (envelopeId != Postman.kUnknownEnvelopeId) {
- Postman.getInstance().destroyEnvelope(envelopeId);
- }
-
- 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 = GeckoAppShell.getContext().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("GeckoSmsManager", "The id we received is higher than the higher allowed value.");
- return -1;
- } catch (Exception e) {
- Log.e("GeckoSmsManager", "Something went wrong when trying to write a sent message", e);
- return -1;
- }
- }
-
- @Override
- 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 = GeckoAppShell.getContext().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 = getGeckoDeliveryStatus(cursor.getInt(cursor.getColumnIndex("status")));
- receiver = cursor.getString(cursor.getColumnIndex("address"));
- } else {
- throw new InvalidTypeException();
- }
-
- 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("GeckoSmsManager", "Message id " + mMessageId + " not found");
- notifyGetSmsFailed(kNotFoundError, mRequestId);
- } catch (UnmatchingIdException e) {
- Log.e("GeckoSmsManager", "Requested message id (" + mMessageId +
- ") is different from the one we got.");
- notifyGetSmsFailed(kUnknownError, mRequestId);
- } catch (TooManyResultsException e) {
- Log.e("GeckoSmsManager", "Get too many results for id " + mMessageId);
- notifyGetSmsFailed(kUnknownError, mRequestId);
- } catch (InvalidTypeException e) {
- Log.i("GeckoSmsManager", "Message has an invalid type, we ignore it.");
- notifyGetSmsFailed(kNotFoundError, mRequestId);
- } catch (Exception e) {
- Log.e("GeckoSmsManager", "Error while trying to get message", e);
- notifyGetSmsFailed(kUnknownError, mRequestId);
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- }
- }
-
- if (!SmsIOThread.getInstance().execute(new GetMessageRunnable(aMessageId, aRequestId))) {
- Log.e("GeckoSmsManager", "Failed to add GetMessageRunnable to the SmsIOThread");
- notifyGetSmsFailed(kUnknownError, aRequestId);
- }
- }
-
- @Override
- 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 = GeckoAppShell.getContext().getContentResolver();
- Uri message = ContentUris.withAppendedId(kSmsContentUri, mMessageId);
-
- int count = cr.delete(message, null, null);
-
- if (count > 1) {
- throw new TooManyResultsException();
- }
-
- notifySmsDeleted(count == 1, mRequestId);
- } catch (TooManyResultsException e) {
- Log.e("GeckoSmsManager", "Delete more than one message?", e);
- notifySmsDeleteFailed(kUnknownError, mRequestId);
- } catch (Exception e) {
- Log.e("GeckoSmsManager", "Error while trying to delete a message", e);
- notifySmsDeleteFailed(kUnknownError, mRequestId);
- }
- }
- }
-
- if (!SmsIOThread.getInstance().execute(new DeleteMessageRunnable(aMessageId, aRequestId))) {
- Log.e("GeckoSmsManager", "Failed to add GetMessageRunnable to the SmsIOThread");
- notifySmsDeleteFailed(kUnknownError, aRequestId);
- }
- }
-
- @Override
- 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 = GeckoAppShell.getContext().getContentResolver();
- cursor = cr.query(kSmsContentUri, kRequiredMessageRows, restrictionText, null,
- mReverse ? "date DESC" : "date ASC");
-
- if (cursor.getCount() == 0) {
- 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 = getGeckoDeliveryStatus(cursor.getInt(cursor.getColumnIndex("status")));
- receiver = cursor.getString(cursor.getColumnIndex("address"));
- } else {
- throw new UnexpectedDeliveryStateException();
- }
-
- int listId = MessagesListManager.getInstance().add(cursor);
- closeCursor = false;
- 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("GeckoSmsManager", "Unexcepted delivery state type", e);
- notifyReadingMessageListFailed(kUnknownError, mRequestId);
- } catch (Exception e) {
- Log.e("GeckoSmsManager", "Error while trying to create a message list cursor", e);
- 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("GeckoSmsManager", "Failed to add CreateMessageListRunnable to the SmsIOThread");
- notifyReadingMessageListFailed(kUnknownError, aRequestId);
- }
- }
-
- @Override
- 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);
- 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 = getGeckoDeliveryStatus(cursor.getInt(cursor.getColumnIndex("status")));
- receiver = cursor.getString(cursor.getColumnIndex("address"));
- } else {
- throw new UnexpectedDeliveryStateException();
- }
-
- int listId = MessagesListManager.getInstance().add(cursor);
- 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("GeckoSmsManager", "Unexcepted delivery state type", e);
- notifyReadingMessageListFailed(kUnknownError, mRequestId);
- } catch (Exception e) {
- Log.e("GeckoSmsManager", "Error while trying to get the next message of a list", e);
- notifyReadingMessageListFailed(kUnknownError, mRequestId);
- }
- }
- }
-
- if (!SmsIOThread.getInstance().execute(new GetNextMessageInListRunnable(aListId, aRequestId))) {
- Log.e("GeckoSmsManager", "Failed to add GetNextMessageInListRunnable to the SmsIOThread");
- notifyReadingMessageListFailed(kUnknownError, aRequestId);
- }
- }
-
- @Override
- public void clearMessageList(int aListId) {
- MessagesListManager.getInstance().remove(aListId);
- }
-
- @Override
- public void stop() {
- GeckoAppShell.getContext().unregisterReceiver(this);
- }
-
- @Override
- public void shutdown() {
- SmsIOThread.getInstance().interrupt();
- MessagesListManager.getInstance().clear();
- }
-
- private int getGeckoDeliveryStatus(int aDeliveryStatus) {
- if (aDeliveryStatus == kInternalDeliveryStatusNone) {
- return kDeliveryStatusNotApplicable;
- }
- if (aDeliveryStatus >= kInternalDeliveryStatusFailed) {
- return kDeliveryStatusError;
- }
- if (aDeliveryStatus >= kInternalDeliveryStatusPending) {
- return kDeliveryStatusPending;
- }
- return kDeliveryStatusSuccess;
- }
-
- private int getGeckoMessageClass(MessageClass aMessageClass) {
- switch (aMessageClass) {
- case CLASS_0:
- return kMessageClassClass0;
- case CLASS_1:
- return kMessageClassClass1;
- case CLASS_2:
- return kMessageClassClass2;
- case CLASS_3:
- return kMessageClassClass3;
- default:
- return kMessageClassNormal;
- }
- }
-
- class IdTooHighException extends Exception {
- private static final long serialVersionUID = 29935575131092050L;
- }
-
- class InvalidTypeException extends Exception {
- private static final long serialVersionUID = 47436856832535912L;
- }
-
- class NotFoundException extends Exception {
- private static final long serialVersionUID = 1940676816633984L;
- }
-
- class TooManyResultsException extends Exception {
- private static final long serialVersionUID = 51883196784325305L;
- }
-
- class UnexpectedDeliveryStateException extends Exception {
- private static final long serialVersionUID = 494122763684005716L;
- }
-
- class UnmatchingIdException extends Exception {
- private static final long serialVersionUID = 158467542575633280L;
- }
-
- private static native void notifySmsReceived(String aSender, String aBody, int aMessageClass, long aTimestamp);
- private static native void notifySmsSent(int aId, String aReceiver, String aBody, long aTimestamp, int aRequestId);
- private static native void notifySmsDelivery(int aId, int aDeliveryStatus, String aReceiver, String aBody, long aTimestamp);
- private static native void notifySmsSendFailed(int aError, int aRequestId);
- private static native void notifyGetSms(int aId, int aDeliveryStatus, String aReceiver, String aSender, String aBody, long aTimestamp, int aRequestId);
- private static native void notifyGetSmsFailed(int aError, int aRequestId);
- private static native void notifySmsDeleted(boolean aDeleted, int aRequestId);
- private static native void notifySmsDeleteFailed(int aError, int aRequestId);
- private static native void notifyNoMessageInList(int aRequestId);
- private static native void notifyListCreated(int aListId, int aMessageId, int aDeliveryStatus, String aReceiver, String aSender, String aBody, long aTimestamp, int aRequestId);
- private static native void notifyGotNextMessage(int aMessageId, int aDeliveryStatus, String aReceiver, String aSender, String aBody, long aTimestamp, int aRequestId);
- private static native void notifyReadingMessageListFailed(int aError, int aRequestId);
-}
diff --git a/mobile/android/base/GeckoThread.java b/mobile/android/base/GeckoThread.java
deleted file mode 100644
index 830281a10..000000000
--- a/mobile/android/base/GeckoThread.java
+++ /dev/null
@@ -1,149 +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.gecko;
-
-import org.mozilla.gecko.mozglue.GeckoLoader;
-import org.mozilla.gecko.util.GeckoEventListener;
-
-import org.json.JSONObject;
-
-import android.content.Intent;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.os.SystemClock;
-import android.util.Log;
-import android.app.Activity;
-
-
-import java.util.Locale;
-
-public class GeckoThread extends Thread implements GeckoEventListener {
- private static final String LOGTAG = "GeckoThread";
-
- public enum LaunchState {
- Launching,
- WaitForDebugger,
- Launched,
- GeckoRunning,
- GeckoExiting
- };
-
- private static LaunchState sLaunchState = LaunchState.Launching;
-
- private Intent mIntent;
- private final String mUri;
-
- GeckoThread(Intent intent, String uri) {
- mIntent = intent;
- mUri = uri;
- setName("Gecko");
- GeckoAppShell.getEventDispatcher().registerEventListener("Gecko:Ready", this);
- }
-
- private String initGeckoEnvironment() {
- // At some point while loading the gecko libs our default locale gets set
- // so just save it to locale here and reset it as default after the join
- Locale locale = Locale.getDefault();
-
- if (locale.toString().equalsIgnoreCase("zh_hk")) {
- locale = Locale.TRADITIONAL_CHINESE;
- Locale.setDefault(locale);
- }
-
- Context app = GeckoAppShell.getContext();
- String resourcePath = "";
- Resources res = null;
- String[] pluginDirs = null;
- try {
- pluginDirs = GeckoAppShell.getPluginDirectories();
- } catch (Exception e) {
- Log.w(LOGTAG, "Caught exception getting plugin dirs.", e);
- }
-
- if (app instanceof Activity) {
- Activity activity = (Activity)app;
- resourcePath = activity.getApplication().getPackageResourcePath();
- res = activity.getBaseContext().getResources();
- GeckoLoader.setupGeckoEnvironment(activity, pluginDirs, GeckoProfile.get(app).getFilesDir().getPath());
- }
- GeckoLoader.loadSQLiteLibs(app, resourcePath);
- GeckoLoader.loadNSSLibs(app, resourcePath);
- GeckoLoader.loadGeckoLibs(app, resourcePath);
-
- Locale.setDefault(locale);
-
- Configuration config = res.getConfiguration();
- config.locale = locale;
- res.updateConfiguration(config, res.getDisplayMetrics());
-
- return resourcePath;
- }
-
- private String getTypeFromAction(String action) {
- if (action != null && action.startsWith(GeckoApp.ACTION_WEBAPP_PREFIX)) {
- return "-webapp";
- }
- if (GeckoApp.ACTION_BOOKMARK.equals(action)) {
- return "-bookmark";
- }
- return null;
- }
-
- private String addCustomProfileArg(String args) {
- String profile = GeckoAppShell.getGeckoInterface() == null || GeckoApp.sIsUsingCustomProfile ? "" : (" -P " + GeckoAppShell.getGeckoInterface().getProfile().getName());
- return (args != null ? args : "") + profile;
- }
-
- @Override
- public void run() {
- String path = initGeckoEnvironment();
-
- Log.w(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - runGecko");
-
- String args = addCustomProfileArg(mIntent.getStringExtra("args"));
- String type = getTypeFromAction(mIntent.getAction());
- mIntent = null;
-
- // and then fire us up
- Log.i(LOGTAG, "RunGecko - args = " + args);
- GeckoAppShell.runGecko(path, args, mUri, type);
- }
-
- @Override
- public void handleMessage(String event, JSONObject message) {
- if ("Gecko:Ready".equals(event)) {
- GeckoAppShell.getEventDispatcher().unregisterEventListener(event, this);
- setLaunchState(LaunchState.GeckoRunning);
- GeckoAppShell.sendPendingEventsToGecko();
- }
- }
-
- public static boolean checkLaunchState(LaunchState checkState) {
- synchronized (sLaunchState) {
- return sLaunchState == checkState;
- }
- }
-
- static void setLaunchState(LaunchState setState) {
- synchronized (sLaunchState) {
- sLaunchState = setState;
- }
- }
-
- /**
- * Set the launch state to <code>setState</code> and return true if the current launch
- * state is <code>checkState</code>; otherwise do nothing and return false.
- */
- static boolean checkAndSetLaunchState(LaunchState checkState, LaunchState setState) {
- synchronized (sLaunchState) {
- if (sLaunchState != checkState)
- return false;
- sLaunchState = setState;
- return true;
- }
- }
-}
diff --git a/mobile/android/base/GeckoUpdateReceiver.java b/mobile/android/base/GeckoUpdateReceiver.java
deleted file mode 100644
index f73c42e40..000000000
--- a/mobile/android/base/GeckoUpdateReceiver.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; 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.gecko;
-
-import org.mozilla.gecko.updater.UpdateServiceHelper;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-
-public class GeckoUpdateReceiver extends BroadcastReceiver
-{
- @Override
- public void onReceive(Context context, Intent intent) {
- if (UpdateServiceHelper.ACTION_CHECK_UPDATE_RESULT.equals(intent.getAction())) {
- String result = intent.getStringExtra("result");
- if (GeckoAppShell.getGeckoInterface() != null && result != null) {
- GeckoAppShell.getGeckoInterface().notifyCheckUpdateResult(result);
- }
- }
- }
-}
diff --git a/mobile/android/base/GeckoView.java b/mobile/android/base/GeckoView.java
deleted file mode 100644
index 414e85369..000000000
--- a/mobile/android/base/GeckoView.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; 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.gecko;
-
-import org.mozilla.gecko.db.BrowserDB;
-import org.mozilla.gecko.gfx.LayerView;
-import org.mozilla.gecko.util.GeckoEventListener;
-import org.mozilla.gecko.util.ThreadUtils;
-
-import org.json.JSONObject;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.net.Uri;
-import android.os.Bundle;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-import android.os.Handler;
-
-public class GeckoView extends LayerView
- implements GeckoEventListener, ContextGetter {
- static GeckoThread sGeckoThread;
-
- public GeckoView(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GeckoView);
- String url = a.getString(R.styleable.GeckoView_url);
- a.recycle();
-
- Intent intent;
- if (url == null) {
- intent = new Intent(Intent.ACTION_MAIN);
- } else {
- intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
- GeckoAppShell.sendEventToGecko(GeckoEvent.createURILoadEvent(url));
- }
- GeckoAppShell.setContextGetter(this);
- if (context instanceof Activity) {
- Tabs tabs = Tabs.getInstance();
- tabs.attachToActivity((Activity) context);
- }
- GeckoProfile profile = GeckoProfile.get(context);
- BrowserDB.initialize(profile.getName());
- GeckoAppShell.registerEventListener("Gecko:Ready", this);
-
- sGeckoThread = new GeckoThread(intent, url);
- ThreadUtils.setGeckoThread(sGeckoThread);
- ThreadUtils.setUiThread(Thread.currentThread(), new Handler());
- initializeView(GeckoAppShell.getEventDispatcher());
- if (GeckoThread.checkAndSetLaunchState(GeckoThread.LaunchState.Launching, GeckoThread.LaunchState.Launched)) {
- GeckoAppShell.setLayerView(this);
- sGeckoThread.start();
- }
- }
-
- @Override
- public void onWindowFocusChanged(boolean hasFocus) {
- super.onWindowFocusChanged(hasFocus);
-
- if (hasFocus) {
- setBackgroundDrawable(null);
- }
- }
-
- public void loadUrl(String uri) {
- Tabs.getInstance().loadUrl(uri);
- }
-
- public void handleMessage(String event, JSONObject message) {
- if (event.equals("Gecko:Ready")) {
- GeckoThread.setLaunchState(GeckoThread.LaunchState.GeckoRunning);
- Tab selectedTab = Tabs.getInstance().getSelectedTab();
- if (selectedTab != null)
- Tabs.getInstance().notifyListeners(selectedTab, Tabs.TabEvents.SELECTED);
- geckoConnected();
- GeckoAppShell.setLayerClient(getLayerClient());
- GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Viewport:Flush", null));
- show();
- requestRender();
- }
- }
-
- public static void setGeckoInterface(GeckoAppShell.GeckoInterface aGeckoInterface) {
- GeckoAppShell.setGeckoInterface(aGeckoInterface);
- }
-}
diff --git a/mobile/android/base/GeckoView.java.frag b/mobile/android/base/GeckoView.java.frag
deleted file mode 100644
index c44f53dd4..000000000
--- a/mobile/android/base/GeckoView.java.frag
+++ /dev/null
@@ -1,126 +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/. */
-
-package org.mozilla.gecko;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.util.AttributeSet;
-import android.widget.@VIEWTYPE@;
-
-public class Gecko@VIEWTYPE@ extends @VIEWTYPE@
- implements LightweightTheme.OnChangeListener {
- private GeckoActivity mActivity;
- private static final int[] STATE_PRIVATE_MODE = { R.attr.state_private };
- private static final int[] STATE_LIGHT = { R.attr.state_light };
- private static final int[] STATE_DARK = { R.attr.state_dark };
-
- private boolean mIsPrivate = false;
- private boolean mIsLight = false;
- private boolean mIsDark = false;
- private boolean mAutoUpdateTheme = true;
-
- public Gecko@VIEWTYPE@(Context context, AttributeSet attrs) {
- super(context, attrs);
- mActivity = (GeckoActivity) context;
-
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LightweightTheme);
- mAutoUpdateTheme = a.getBoolean(R.styleable.LightweightTheme_autoUpdateTheme, true);
- a.recycle();
- }
-
- @Override
- public void onAttachedToWindow() {
- super.onAttachedToWindow();
-
- if (mAutoUpdateTheme)
- mActivity.getLightweightTheme().addListener(this);
- }
-
- @Override
- public void onDetachedFromWindow() {
- super.onDetachedFromWindow();
-
- if (mAutoUpdateTheme)
- mActivity.getLightweightTheme().removeListener(this);
- }
-
- @Override
- public int[] onCreateDrawableState(int extraSpace) {
- final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
-
- if (mIsPrivate)
- mergeDrawableStates(drawableState, STATE_PRIVATE_MODE);
- else if (mIsLight)
- mergeDrawableStates(drawableState, STATE_LIGHT);
- else if (mIsDark)
- mergeDrawableStates(drawableState, STATE_DARK);
-
- return drawableState;
- }
-
- @Override
- public void onLightweightThemeChanged() {
- if (mAutoUpdateTheme && mActivity.getLightweightTheme().isEnabled())
- setTheme(mActivity.getLightweightTheme().isLightTheme());
- }
-
- @Override
- public void onLightweightThemeReset() {
- if (mAutoUpdateTheme)
- resetTheme();
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- onLightweightThemeChanged();
- }
-
- public boolean isPrivateMode() {
- return mIsPrivate;
- }
-
- public void setPrivateMode(boolean isPrivate) {
- if (mIsPrivate != isPrivate) {
- mIsPrivate = isPrivate;
- refreshDrawableState();
- }
- }
-
- public void setTheme(boolean isLight) {
- // Set the theme only if it is different from existing theme.
- if ((isLight && mIsLight != isLight) ||
- (!isLight && mIsDark == isLight)) {
- if (isLight) {
- mIsLight = true;
- mIsDark = false;
- } else {
- mIsLight = false;
- mIsDark = true;
- }
-
- refreshDrawableState();
- }
- }
-
- public void resetTheme() {
- if (mIsLight || mIsDark) {
- mIsLight = false;
- mIsDark = false;
- refreshDrawableState();
- }
- }
-
- public void setAutoUpdateTheme(boolean autoUpdateTheme) {
- if (mAutoUpdateTheme != autoUpdateTheme) {
- mAutoUpdateTheme = autoUpdateTheme;
-
- if (mAutoUpdateTheme)
- mActivity.getLightweightTheme().addListener(this);
- else
- mActivity.getLightweightTheme().removeListener(this);
- }
- }
-}
diff --git a/mobile/android/base/GeckoViewsFactory.java b/mobile/android/base/GeckoViewsFactory.java
deleted file mode 100644
index 899e10807..000000000
--- a/mobile/android/base/GeckoViewsFactory.java
+++ /dev/null
@@ -1,133 +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/. */
-
-package org.mozilla.gecko;
-
-import org.mozilla.gecko.gfx.LayerView;
-import org.mozilla.gecko.menu.GeckoMenu;
-import org.mozilla.gecko.menu.MenuItemActionBar;
-import org.mozilla.gecko.menu.MenuItemDefault;
-import org.mozilla.gecko.widget.AboutHomeView;
-import org.mozilla.gecko.widget.AddonsSection;
-import org.mozilla.gecko.widget.FaviconView;
-import org.mozilla.gecko.widget.IconTabWidget;
-import org.mozilla.gecko.widget.LastTabsSection;
-import org.mozilla.gecko.widget.LinkTextView;
-import org.mozilla.gecko.widget.PromoBox;
-import org.mozilla.gecko.widget.RemoteTabsSection;
-import org.mozilla.gecko.widget.TabRow;
-import org.mozilla.gecko.widget.ThumbnailView;
-import org.mozilla.gecko.widget.TopSitesView;
-
-import android.content.Context;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-
-import java.lang.reflect.Constructor;
-import java.util.HashMap;
-import java.util.Map;
-
-public final class GeckoViewsFactory implements LayoutInflater.Factory {
- private static final String LOGTAG = "GeckoViewsFactory";
-
- private static final String GECKO_VIEW_IDENTIFIER = "org.mozilla.gecko.";
- private static final int GECKO_VIEW_IDENTIFIER_LENGTH = GECKO_VIEW_IDENTIFIER.length();
-
- private static final String GECKO_IDENTIFIER = "Gecko.";
- private static final int GECKO_IDENTIFIER_LENGTH = GECKO_IDENTIFIER.length();
-
- private final Map<String, Constructor<? extends View>> mFactoryMap;
-
- private GeckoViewsFactory() {
- // initialize the hashmap to a capacity that is a prime number greater than
- // (size * 4/3). The size is the number of items we expect to put in it, and
- // 4/3 is the inverse of the default load factor.
- mFactoryMap = new HashMap<String, Constructor<? extends View>>(53);
- Class<Context> arg1Class = Context.class;
- Class<AttributeSet> arg2Class = AttributeSet.class;
- try {
- mFactoryMap.put("AboutHomeView", AboutHomeView.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("AddonsSection", AddonsSection.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("LastTabsSection", LastTabsSection.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("PromoBox", PromoBox.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("RemoteTabsSection", RemoteTabsSection.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("TopSitesView", TopSitesView.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("AwesomeBarTabs", AwesomeBarTabs.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("AwesomeBarTabs$BackgroundLayout", AwesomeBarTabs.BackgroundLayout.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("BackButton", BackButton.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("BrowserToolbarBackground", BrowserToolbarBackground.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("CheckableLinearLayout", CheckableLinearLayout.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("FormAssistPopup", FormAssistPopup.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("ForwardButton", ForwardButton.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("GeckoApp$MainLayout", GeckoApp.MainLayout.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("LinkTextView", LinkTextView.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("menu.MenuItemActionBar", MenuItemActionBar.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("menu.MenuItemDefault", MenuItemDefault.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("menu.GeckoMenu$DefaultActionItemBar", GeckoMenu.DefaultActionItemBar.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("FindInPageBar", FindInPageBar.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("IconTabWidget", IconTabWidget.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("RemoteTabs", RemoteTabs.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("ShapedButton", ShapedButton.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("TabRow", TabRow.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("TabsPanel", TabsPanel.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("TabsPanel$TabsListContainer", TabsPanel.TabsListContainer.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("TabsPanel$TabsPanelToolbar", TabsPanel.TabsPanelToolbar.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("TabsTray", TabsTray.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("ThumbnailView", ThumbnailView.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("TextSelectionHandle", TextSelectionHandle.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("gfx.LayerView", LayerView.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("AllCapsTextView", AllCapsTextView.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("Button", GeckoButton.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("EditText", GeckoEditText.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("FrameLayout", GeckoFrameLayout.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("ImageButton", GeckoImageButton.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("ImageView", GeckoImageView.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("LinearLayout", GeckoLinearLayout.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("RelativeLayout", GeckoRelativeLayout.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("TextSwitcher", GeckoTextSwitcher.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("TextView", GeckoTextView.class.getConstructor(arg1Class, arg2Class));
- mFactoryMap.put("FaviconView", FaviconView.class.getConstructor(arg1Class, arg2Class));
- } catch (NoSuchMethodException nsme) {
- Log.e(LOGTAG, "Unable to initialize views factory", nsme);
- }
- }
-
- // Making this a singleton class.
- private static final GeckoViewsFactory INSTANCE = new GeckoViewsFactory();
-
- public static GeckoViewsFactory getInstance() {
- return INSTANCE;
- }
-
- @Override
- public View onCreateView(String name, Context context, AttributeSet attrs) {
- if (!TextUtils.isEmpty(name)) {
- String viewName = null;
-
- if (name.startsWith(GECKO_VIEW_IDENTIFIER))
- viewName = name.substring(GECKO_VIEW_IDENTIFIER_LENGTH);
- else if (name.startsWith(GECKO_IDENTIFIER))
- viewName = name.substring(GECKO_IDENTIFIER_LENGTH);
- else
- return null;
-
- Constructor<? extends View> constructor = mFactoryMap.get(viewName);
- if (constructor != null) {
- try {
- return constructor.newInstance(context, attrs);
- } catch (Exception e) {
- Log.e(LOGTAG, "Unable to instantiate view " + name, e);
- return null;
- }
- }
-
- Log.d(LOGTAG, "Warning: unknown custom view: " + name);
- }
-
- return null;
- }
-}
diff --git a/mobile/android/base/gfx/GeckoLayerClient.java b/mobile/android/base/gfx/GeckoLayerClient.java
deleted file mode 100644
index 034dfeafa..000000000
--- a/mobile/android/base/gfx/GeckoLayerClient.java
+++ /dev/null
@@ -1,978 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; 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.gecko.gfx;
-
-import org.mozilla.gecko.BrowserApp;
-import org.mozilla.gecko.GeckoAppShell;
-import org.mozilla.gecko.GeckoEvent;
-import org.mozilla.gecko.Tab;
-import org.mozilla.gecko.Tabs;
-import org.mozilla.gecko.ZoomConstraints;
-import org.mozilla.gecko.util.EventDispatcher;
-import org.mozilla.gecko.util.FloatUtils;
-import org.mozilla.gecko.util.ThreadUtils;
-
-import android.content.Context;
-import android.graphics.PointF;
-import android.graphics.RectF;
-import android.os.SystemClock;
-import android.util.DisplayMetrics;
-import android.util.Log;
-
-public class GeckoLayerClient implements LayerView.Listener, PanZoomTarget
-{
- private static final String LOGTAG = "GeckoLayerClient";
-
- private LayerRenderer mLayerRenderer;
- private boolean mLayerRendererInitialized;
-
- private Context mContext;
- private IntSize mScreenSize;
- private IntSize mWindowSize;
- private DisplayPortMetrics mDisplayPort;
-
- private boolean mRecordDrawTimes;
- private final DrawTimingQueue mDrawTimingQueue;
-
- private VirtualLayer mRootLayer;
-
- /* The Gecko viewport as per the UI thread. Must be touched only on the UI thread.
- * If any events being sent to Gecko that are relative to the Gecko viewport position,
- * they must (a) be relative to this viewport, and (b) be sent on the UI thread to
- * avoid races. As long as these two conditions are satisfied, and the events being
- * sent to Gecko are processed in FIFO order, the events will properly be relative
- * to the Gecko viewport position. Note that if Gecko updates its viewport independently,
- * we get notified synchronously and also update this on the UI thread.
- */
- private ImmutableViewportMetrics mGeckoViewport;
-
- /*
- * The viewport metrics being used to draw the current frame. This is only
- * accessed by the compositor thread, and so needs no synchronisation.
- */
- private ImmutableViewportMetrics mFrameMetrics;
-
- /* Used by robocop for testing purposes */
- private DrawListener mDrawListener;
-
- /* Used as temporaries by syncViewportInfo */
- private final ViewTransform mCurrentViewTransform;
- private final RectF mCurrentViewTransformMargins;
-
- /* Used as the return value of progressiveUpdateCallback */
- private final ProgressiveUpdateData mProgressiveUpdateData;
- private DisplayPortMetrics mProgressiveUpdateDisplayPort;
- private boolean mLastProgressiveUpdateWasLowPrecision;
- private boolean mProgressiveUpdateWasInDanger;
-
- private boolean mForceRedraw;
-
- /* The current viewport metrics.
- * This is volatile so that we can read and write to it from different threads.
- * We avoid synchronization to make getting the viewport metrics from
- * the compositor as cheap as possible. The viewport is immutable so
- * we don't need to worry about anyone mutating it while we're reading from it.
- * Specifically:
- * 1) reading mViewportMetrics from any thread is fine without synchronization
- * 2) writing to mViewportMetrics requires synchronizing on the layer controller object
- * 3) whenver reading multiple fields from mViewportMetrics without synchronization (i.e. in
- * case 1 above) you should always frist grab a local copy of the reference, and then use
- * that because mViewportMetrics might get reassigned in between reading the different
- * fields. */
- private volatile ImmutableViewportMetrics mViewportMetrics;
- private OnMetricsChangedListener mViewportChangeListener;
-
- private ZoomConstraints mZoomConstraints;
-
- private boolean mGeckoIsReady;
-
- private final PanZoomController mPanZoomController;
- private final LayerMarginsAnimator mMarginsAnimator;
- private LayerView mView;
-
- /* This flag is true from the time that browser.js detects a first-paint is about to start,
- * to the time that we receive the first-paint composite notification from the compositor.
- * Note that there is a small race condition with this; if there are two paints that both
- * have the first-paint flag set, and the second paint happens concurrently with the
- * composite for the first paint, then this flag may be set to true prematurely. Fixing this
- * is possible but risky; see https://bugzilla.mozilla.org/show_bug.cgi?id=797615#c751
- */
- private volatile boolean mContentDocumentIsDisplayed;
-
- public GeckoLayerClient(Context context, LayerView view, EventDispatcher eventDispatcher) {
- // we can fill these in with dummy values because they are always written
- // to before being read
- mContext = context;
- mScreenSize = new IntSize(0, 0);
- mWindowSize = new IntSize(0, 0);
- mDisplayPort = new DisplayPortMetrics();
- mRecordDrawTimes = true;
- mDrawTimingQueue = new DrawTimingQueue();
- mCurrentViewTransform = new ViewTransform(0, 0, 1);
- mCurrentViewTransformMargins = new RectF();
- mProgressiveUpdateData = new ProgressiveUpdateData();
- mProgressiveUpdateDisplayPort = new DisplayPortMetrics();
- mLastProgressiveUpdateWasLowPrecision = false;
- mProgressiveUpdateWasInDanger = false;
-
- mForceRedraw = true;
- DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
- mViewportMetrics = new ImmutableViewportMetrics(displayMetrics)
- .setViewportSize(view.getWidth(), view.getHeight());
- mFrameMetrics = mViewportMetrics;
- mZoomConstraints = new ZoomConstraints(false);
-
- mPanZoomController = PanZoomController.Factory.create(this, view, eventDispatcher);
- mMarginsAnimator = new LayerMarginsAnimator(this, view);
- mView = view;
- mView.setListener(this);
- mContentDocumentIsDisplayed = true;
- }
-
- /** Attaches to root layer so that Gecko appears. */
- public void notifyGeckoReady() {
- mGeckoIsReady = true;
-
- mRootLayer = new VirtualLayer(new IntSize(mView.getWidth(), mView.getHeight()));
- mLayerRenderer = mView.getRenderer();
-
- sendResizeEventIfNecessary(true);
-
- DisplayPortCalculator.initPrefs();
-
- // Gecko being ready is one of the two conditions (along with having an available
- // surface) that cause us to create the compositor. So here, now that we know gecko
- // is ready, call createCompositor() to see if we can actually do the creation.
- // This needs to run on the UI thread so that the surface validity can't change on
- // us while we're in the middle of creating the compositor.
- mView.post(new Runnable() {
- @Override
- public void run() {
- mView.getGLController().createCompositor();
- }
- });
- }
-
- public void destroy() {
- mPanZoomController.destroy();
- mMarginsAnimator.destroy();
- }
-
- /**
- * Returns true if this client is fine with performing a redraw operation or false if it
- * would prefer that the action didn't take place.
- */
- private boolean getRedrawHint() {
- if (mForceRedraw) {
- mForceRedraw = false;
- return true;
- }
-
- if (!mPanZoomController.getRedrawHint()) {
- return false;
- }
-
- return DisplayPortCalculator.aboutToCheckerboard(mViewportMetrics,
- mPanZoomController.getVelocityVector(), mDisplayPort);
- }
-
- Layer getRoot() {
- return mGeckoIsReady ? mRootLayer : null;
- }
-
- public LayerView getView() {
- return mView;
- }
-
- public FloatSize getViewportSize() {
- return mViewportMetrics.getSize();
- }
-
- /**
- * The view calls this function to indicate that the viewport changed size. It must hold the
- * monitor while calling it.
- *
- * TODO: Refactor this to use an interface. Expose that interface only to the view and not
- * to the layer client. That way, the layer client won't be tempted to call this, which might
- * result in an infinite loop.
- */
- void setViewportSize(int width, int height) {
- mViewportMetrics = mViewportMetrics.setViewportSize(width, height);
-
- if (mGeckoIsReady) {
- // here we send gecko a resize message. The code in browser.js is responsible for
- // picking up on that resize event, modifying the viewport as necessary, and informing
- // us of the new viewport.
- sendResizeEventIfNecessary(true);
- // the following call also sends gecko a message, which will be processed after the resize
- // message above has updated the viewport. this message ensures that if we have just put
- // focus in a text field, we scroll the content so that the text field is in view.
- GeckoAppShell.viewSizeChanged();
- }
- }
-
- PanZoomController getPanZoomController() {
- return mPanZoomController;
- }
-
- LayerMarginsAnimator getLayerMarginsAnimator() {
- return mMarginsAnimator;
- }
-
- /* Informs Gecko that the screen size has changed. */
- private void sendResizeEventIfNecessary(boolean force) {
- DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
-
- IntSize newScreenSize = new IntSize(metrics.widthPixels, metrics.heightPixels);
- IntSize newWindowSize = new IntSize(mView.getWidth(), mView.getHeight());
-
- boolean screenSizeChanged = !mScreenSize.equals(newScreenSize);
- boolean windowSizeChanged = !mWindowSize.equals(newWindowSize);
-
- if (!force && !screenSizeChanged && !windowSizeChanged) {
- return;
- }
-
- mScreenSize = newScreenSize;
- mWindowSize = newWindowSize;
-
- if (screenSizeChanged) {
- Log.d(LOGTAG, "Screen-size changed to " + mScreenSize);
- }
-
- if (windowSizeChanged) {
- Log.d(LOGTAG, "Window-size changed to " + mWindowSize);
- }
-
- GeckoEvent event = GeckoEvent.createSizeChangedEvent(mWindowSize.width, mWindowSize.height,
- mScreenSize.width, mScreenSize.height);
- GeckoAppShell.sendEventToGecko(event);
- GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Window:Resize", ""));
- }
-
- /** Sets the current page rect. You must hold the monitor while calling this. */
- private void setPageRect(RectF rect, RectF cssRect) {
- // Since the "rect" is always just a multiple of "cssRect" we don't need to
- // check both; this function assumes that both "rect" and "cssRect" are relative
- // the zoom factor in mViewportMetrics.
- if (mViewportMetrics.getCssPageRect().equals(cssRect))
- return;
-
- mViewportMetrics = mViewportMetrics.setPageRect(rect, cssRect);
-
- // Page size is owned by the layer client, so no need to notify it of
- // this change.
-
- post(new Runnable() {
- @Override
- public void run() {
- mPanZoomController.pageRectUpdated();
- mView.requestRender();
- }
- });
- }
-
- /**
- * Derives content document fixed position margins/fixed layer margins from
- * the view margins in the given metrics object.
- */
- private void getFixedMargins(ImmutableViewportMetrics metrics, RectF fixedMargins) {
- fixedMargins.left = 0;
- fixedMargins.top = 0;
- fixedMargins.right = 0;
- fixedMargins.bottom = 0;
-
- // The maximum margins are determined by the scrollable area of the page.
- float maxMarginWidth = Math.max(0, metrics.getPageWidth() - metrics.getWidthWithoutMargins());
- float maxMarginHeight = Math.max(0, metrics.getPageHeight() - metrics.getHeightWithoutMargins());
-
- PointF offset = metrics.getMarginOffset();
- RectF overscroll = metrics.getOverscroll();
- if (offset.x >= 0) {
- fixedMargins.right = Math.max(0, Math.min(offset.x - overscroll.right, maxMarginWidth));
- } else {
- fixedMargins.left = Math.max(0, Math.min(-offset.x - overscroll.left, maxMarginWidth));
- }
- if (offset.y >= 0) {
- fixedMargins.bottom = Math.max(0, Math.min(offset.y - overscroll.bottom, maxMarginHeight));
- } else {
- fixedMargins.top = Math.max(0, Math.min(-offset.y - overscroll.top, maxMarginHeight));
- }
-
- // Adjust for overscroll. If we're overscrolled on one side, add that
- // distance to the margins of the other side (limiting to the maximum
- // margin size calculated above).
- if (overscroll.left > 0) {
- fixedMargins.right = Math.min(maxMarginWidth - fixedMargins.left,
- fixedMargins.right + overscroll.left);
- } else if (overscroll.right > 0) {
- fixedMargins.left = Math.min(maxMarginWidth - fixedMargins.right,
- fixedMargins.left + overscroll.right);
- }
- if (overscroll.top > 0) {
- fixedMargins.bottom = Math.min(maxMarginHeight - fixedMargins.top,
- fixedMargins.bottom + overscroll.top);
- } else if (overscroll.bottom > 0) {
- fixedMargins.top = Math.min(maxMarginHeight - fixedMargins.bottom,
- fixedMargins.top + overscroll.bottom);
- }
- }
-
- private void adjustViewport(DisplayPortMetrics displayPort) {
- ImmutableViewportMetrics metrics = getViewportMetrics();
- ImmutableViewportMetrics clampedMetrics = metrics.clamp();
-
- RectF margins = new RectF();
- getFixedMargins(metrics, margins);
- clampedMetrics = clampedMetrics.setMargins(
- margins.left, margins.top, margins.right, margins.bottom);
-
- if (displayPort == null) {
- displayPort = DisplayPortCalculator.calculate(metrics, mPanZoomController.getVelocityVector());
- }
-
- mDisplayPort = displayPort;
- mGeckoViewport = clampedMetrics;
-
- if (mRecordDrawTimes) {
- mDrawTimingQueue.add(displayPort);
- }
-
- GeckoAppShell.sendEventToGecko(GeckoEvent.createViewportEvent(clampedMetrics, displayPort));
- }
-
- /** Aborts any pan/zoom animation that is currently in progress. */
- private void abortPanZoomAnimation() {
- if (mPanZoomController != null) {
- post(new Runnable() {
- @Override
- public void run() {
- mPanZoomController.abortAnimation();
- }
- });
- }
- }
-
- /**
- * The different types of Viewport messages handled. All viewport events
- * expect a display-port to be returned, but can handle one not being
- * returned.
- */
- private enum ViewportMessageType {
- UPDATE, // The viewport has changed and should be entirely updated
- PAGE_SIZE // The viewport's page-size has changed
- }
-
- /** Viewport message handler. */
- private DisplayPortMetrics handleViewportMessage(ImmutableViewportMetrics messageMetrics, ViewportMessageType type) {
- synchronized (getLock()) {
- ImmutableViewportMetrics newMetrics;
- ImmutableViewportMetrics oldMetrics = getViewportMetrics();
-
- switch (type) {
- default:
- case UPDATE:
- // Keep the old viewport size
- newMetrics = messageMetrics.setViewportSize(oldMetrics.getWidth(), oldMetrics.getHeight());
- if (!oldMetrics.fuzzyEquals(newMetrics)) {
- abortPanZoomAnimation();
- }
- break;
- case PAGE_SIZE:
- // adjust the page dimensions to account for differences in zoom
- // between the rendered content (which is what Gecko tells us)
- // and our zoom level (which may have diverged).
- float scaleFactor = oldMetrics.zoomFactor / messageMetrics.zoomFactor;
- newMetrics = oldMetrics.setPageRect(RectUtils.scale(messageMetrics.getPageRect(), scaleFactor), messageMetrics.getCssPageRect());
- break;
- }
-
- // Update the Gecko-side viewport metrics. Make sure to do this
- // before modifying the metrics below.
- final ImmutableViewportMetrics geckoMetrics = newMetrics.clamp();
- post(new Runnable() {
- @Override
- public void run() {
- mGeckoViewport = geckoMetrics;
- }
- });
-
- setViewportMetrics(newMetrics, type == ViewportMessageType.UPDATE);
- mDisplayPort = DisplayPortCalculator.calculate(getViewportMetrics(), null);
- }
- return mDisplayPort;
- }
-
- /* This is invoked by JNI on the gecko thread */
- DisplayPortMetrics getDisplayPort(boolean pageSizeUpdate, boolean isBrowserContentDisplayed, int tabId, ImmutableViewportMetrics metrics) {
- Tabs tabs = Tabs.getInstance();
- if (tabs.isSelectedTab(tabs.getTab(tabId)) && isBrowserContentDisplayed) {
- // for foreground tabs, send the viewport update unless the document
- // displayed is different from the content document. In that case, just
- // calculate the display port.
- return handleViewportMessage(metrics, pageSizeUpdate ? ViewportMessageType.PAGE_SIZE : ViewportMessageType.UPDATE);
- } else {
- // for background tabs, request a new display port calculation, so that
- // when we do switch to that tab, we have the correct display port and
- // don't need to draw twice (once to allow the first-paint viewport to
- // get to java, and again once java figures out the display port).
- return DisplayPortCalculator.calculate(metrics, null);
- }
- }
-
- /* This is invoked by JNI on the gecko thread */
- void contentDocumentChanged() {
- mContentDocumentIsDisplayed = false;
- }
-
- /* This is invoked by JNI on the gecko thread */
- boolean isContentDocumentDisplayed() {
- return mContentDocumentIsDisplayed;
- }
-
- // This is called on the Gecko thread to determine if we're still interested
- // in the update of this display-port to continue. We can return true here
- // to abort the current update and continue with any subsequent ones. This
- // is useful for slow-to-render pages when the display-port starts lagging
- // behind enough that continuing to draw it is wasted effort.
- public ProgressiveUpdateData progressiveUpdateCallback(boolean aHasPendingNewThebesContent,
- float x, float y, float width, float height,
- float resolution, boolean lowPrecision) {
- // Reset the checkerboard risk flag when switching to low precision
- // rendering.
- if (lowPrecision && !mLastProgressiveUpdateWasLowPrecision) {
- // Skip low precision rendering until we're at risk of checkerboarding.
- if (!mProgressiveUpdateWasInDanger) {
- mProgressiveUpdateData.abort = true;
- return mProgressiveUpdateData;
- }
- mProgressiveUpdateWasInDanger = false;
- }
- mLastProgressiveUpdateWasLowPrecision = lowPrecision;
-
- // Grab a local copy of the last display-port sent to Gecko and the
- // current viewport metrics to avoid races when accessing them.
- DisplayPortMetrics displayPort = mDisplayPort;
- ImmutableViewportMetrics viewportMetrics = mViewportMetrics;
- mProgressiveUpdateData.setViewport(viewportMetrics);
- mProgressiveUpdateData.abort = false;
-
- // Always abort updates if the resolution has changed. There's no use
- // in drawing at the incorrect resolution.
- if (!FloatUtils.fuzzyEquals(resolution, viewportMetrics.zoomFactor)) {
- Log.d(LOGTAG, "Aborting draw due to resolution change");
- mProgressiveUpdateData.abort = true;
- return mProgressiveUpdateData;
- }
-
- // Store the high precision displayport for comparison when doing low
- // precision updates.
- if (!lowPrecision) {
- if (!FloatUtils.fuzzyEquals(resolution, mProgressiveUpdateDisplayPort.resolution) ||
- !FloatUtils.fuzzyEquals(x, mProgressiveUpdateDisplayPort.getLeft()) ||
- !FloatUtils.fuzzyEquals(y, mProgressiveUpdateDisplayPort.getTop()) ||
- !FloatUtils.fuzzyEquals(x + width, mProgressiveUpdateDisplayPort.getRight()) ||
- !FloatUtils.fuzzyEquals(y + height, mProgressiveUpdateDisplayPort.getBottom())) {
- mProgressiveUpdateDisplayPort =
- new DisplayPortMetrics(x, y, x+width, y+height, resolution);
- }
- }
-
- // If we're not doing low precision draws and we're about to
- // checkerboard, enable low precision drawing.
- if (!lowPrecision && !mProgressiveUpdateWasInDanger) {
- if (DisplayPortCalculator.aboutToCheckerboard(viewportMetrics,
- mPanZoomController.getVelocityVector(), mProgressiveUpdateDisplayPort)) {
- mProgressiveUpdateWasInDanger = true;
- }
- }
-
- // XXX All sorts of rounding happens inside Gecko that becomes hard to
- // account exactly for. Given we align the display-port to tile
- // boundaries (and so they rarely vary by sub-pixel amounts), just
- // check that values are within a couple of pixels of the
- // display-port bounds.
-
- // Never abort drawing if we can't be sure we've sent a more recent
- // display-port. If we abort updating when we shouldn't, we can end up
- // with blank regions on the screen and we open up the risk of entering
- // an endless updating cycle.
- if (Math.abs(displayPort.getLeft() - mProgressiveUpdateDisplayPort.getLeft()) <= 2 &&
- Math.abs(displayPort.getTop() - mProgressiveUpdateDisplayPort.getTop()) <= 2 &&
- Math.abs(displayPort.getBottom() - mProgressiveUpdateDisplayPort.getBottom()) <= 2 &&
- Math.abs(displayPort.getRight() - mProgressiveUpdateDisplayPort.getRight()) <= 2) {
- return mProgressiveUpdateData;
- }
-
- // Abort updates when the display-port no longer contains the visible
- // area of the page (that is, the viewport cropped by the page
- // boundaries).
- // XXX This makes the assumption that we never let the visible area of
- // the page fall outside of the display-port.
- if (Math.max(viewportMetrics.viewportRectLeft, viewportMetrics.pageRectLeft) + 1 < x ||
- Math.max(viewportMetrics.viewportRectTop, viewportMetrics.pageRectTop) + 1 < y ||
- Math.min(viewportMetrics.viewportRectRight, viewportMetrics.pageRectRight) - 1 > x + width ||
- Math.min(viewportMetrics.viewportRectBottom, viewportMetrics.pageRectBottom) - 1 > y + height) {
- Log.d(LOGTAG, "Aborting update due to viewport not in display-port");
- mProgressiveUpdateData.abort = true;
-
- // Enable low-precision drawing, as we're likely to be in danger if
- // this situation has been encountered.
- mProgressiveUpdateWasInDanger = true;
-
- return mProgressiveUpdateData;
- }
-
- // Abort drawing stale low-precision content if there's a more recent
- // display-port in the pipeline.
- if (lowPrecision && !aHasPendingNewThebesContent) {
- mProgressiveUpdateData.abort = true;
- }
- return mProgressiveUpdateData;
- }
-
- void setZoomConstraints(ZoomConstraints constraints) {
- mZoomConstraints = constraints;
- }
-
- void setIsRTL(boolean aIsRTL) {
- synchronized (getLock()) {
- ImmutableViewportMetrics newMetrics = getViewportMetrics().setIsRTL(aIsRTL);
- setViewportMetrics(newMetrics, false);
- }
- }
-
- /** This function is invoked by Gecko via JNI; be careful when modifying signature.
- * The compositor invokes this function just before compositing a frame where the document
- * is different from the document composited on the last frame. In these cases, the viewport
- * information we have in Java is no longer valid and needs to be replaced with the new
- * viewport information provided. setPageRect will never be invoked on the same frame that
- * this function is invoked on; and this function will always be called prior to syncViewportInfo.
- */
- public void setFirstPaintViewport(float offsetX, float offsetY, float zoom,
- float cssPageLeft, float cssPageTop, float cssPageRight, float cssPageBottom) {
- synchronized (getLock()) {
- ImmutableViewportMetrics currentMetrics = getViewportMetrics();
-
- Tab tab = Tabs.getInstance().getSelectedTab();
-
- RectF cssPageRect = new RectF(cssPageLeft, cssPageTop, cssPageRight, cssPageBottom);
- RectF pageRect = RectUtils.scaleAndRound(cssPageRect, zoom);
-
- final ImmutableViewportMetrics newMetrics = currentMetrics
- .setViewportOrigin(offsetX, offsetY)
- .setZoomFactor(zoom)
- .setPageRect(pageRect, cssPageRect)
- .setIsRTL(tab.getIsRTL());
- // Since we have switched to displaying a different document, we need to update any
- // viewport-related state we have lying around. This includes mGeckoViewport and
- // mViewportMetrics. Usually this information is updated via handleViewportMessage
- // while we remain on the same document.
- post(new Runnable() {
- @Override
- public void run() {
- mGeckoViewport = newMetrics;
- }
- });
-
- setViewportMetrics(newMetrics);
-
- mView.setBackgroundColor(tab.getBackgroundColor());
- setZoomConstraints(tab.getZoomConstraints());
-
- // At this point, we have just switched to displaying a different document than we
- // we previously displaying. This means we need to abort any panning/zooming animations
- // that are in progress and send an updated display port request to browser.js as soon
- // as possible. The call to PanZoomController.abortAnimation accomplishes this by calling the
- // forceRedraw function, which sends the viewport to gecko. The display port request is
- // actually a full viewport update, which is fine because if browser.js has somehow moved to
- // be out of sync with this first-paint viewport, then we force them back in sync.
- abortPanZoomAnimation();
-
- // Indicate that the document is about to be composited so the
- // LayerView background can be removed.
- if (mView.getPaintState() == LayerView.PAINT_START) {
- mView.setPaintState(LayerView.PAINT_BEFORE_FIRST);
- }
- }
- DisplayPortCalculator.resetPageState();
- mDrawTimingQueue.reset();
-
- mContentDocumentIsDisplayed = true;
- }
-
- /** This function is invoked by Gecko via JNI; be careful when modifying signature.
- * The compositor invokes this function whenever it determines that the page rect
- * has changed (based on the information it gets from layout). If setFirstPaintViewport
- * is invoked on a frame, then this function will not be. For any given frame, this
- * function will be invoked before syncViewportInfo.
- */
- public void setPageRect(float cssPageLeft, float cssPageTop, float cssPageRight, float cssPageBottom) {
- synchronized (getLock()) {
- RectF cssPageRect = new RectF(cssPageLeft, cssPageTop, cssPageRight, cssPageBottom);
- float ourZoom = getViewportMetrics().zoomFactor;
- setPageRect(RectUtils.scale(cssPageRect, ourZoom), cssPageRect);
- // Here the page size of the document has changed, but the document being displayed
- // is still the same. Therefore, we don't need to send anything to browser.js; any
- // changes we need to make to the display port will get sent the next time we call
- // adjustViewport().
- }
- }
-
- /** This function is invoked by Gecko via JNI; be careful when modifying signature.
- * The compositor invokes this function on every frame to figure out what part of the
- * page to display, and to inform Java of the current display port. Since it is called
- * on every frame, it needs to be ultra-fast.
- * It avoids taking any locks or allocating any objects. We keep around a
- * mCurrentViewTransform so we don't need to allocate a new ViewTransform
- * everytime we're called. NOTE: we might be able to return a ImmutableViewportMetrics
- * which would avoid the copy into mCurrentViewTransform.
- */
- public ViewTransform syncViewportInfo(int x, int y, int width, int height, float resolution, boolean layersUpdated) {
- // getViewportMetrics is thread safe so we don't need to synchronize.
- // We save the viewport metrics here, so we later use it later in
- // createFrame (which will be called by nsWindow::DrawWindowUnderlay on
- // the native side, by the compositor). The viewport
- // metrics can change between here and there, as it's accessed outside
- // of the compositor thread.
- mFrameMetrics = getViewportMetrics();
-
- mCurrentViewTransform.x = mFrameMetrics.viewportRectLeft;
- mCurrentViewTransform.y = mFrameMetrics.viewportRectTop;
- mCurrentViewTransform.scale = mFrameMetrics.zoomFactor;
-
- // Adjust the fixed layer margins so that overscroll subtracts from them.
- getFixedMargins(mFrameMetrics, mCurrentViewTransformMargins);
- mCurrentViewTransform.fixedLayerMarginLeft = mCurrentViewTransformMargins.left;
- mCurrentViewTransform.fixedLayerMarginTop = mCurrentViewTransformMargins.top;
- mCurrentViewTransform.fixedLayerMarginRight = mCurrentViewTransformMargins.right;
- mCurrentViewTransform.fixedLayerMarginBottom = mCurrentViewTransformMargins.bottom;
-
- // Offset the view transform so that it renders in the correct place.
- PointF offset = mFrameMetrics.getMarginOffset();
- mCurrentViewTransform.offsetX = offset.x;
- mCurrentViewTransform.offsetY = offset.y;
-
- mRootLayer.setPositionAndResolution(
- Math.round(x + mCurrentViewTransform.offsetX),
- Math.round(y + mCurrentViewTransform.offsetY),
- Math.round(x + width + mCurrentViewTransform.offsetX),
- Math.round(y + height + mCurrentViewTransform.offsetY),
- resolution);
-
- if (layersUpdated && mRecordDrawTimes) {
- // If we got a layers update, that means a draw finished. Check to see if the area drawn matches
- // one of our requested displayports; if it does calculate the draw time and notify the
- // DisplayPortCalculator
- DisplayPortMetrics drawn = new DisplayPortMetrics(x, y, x + width, y + height, resolution);
- long time = mDrawTimingQueue.findTimeFor(drawn);
- if (time >= 0) {
- long now = SystemClock.uptimeMillis();
- time = now - time;
- mRecordDrawTimes = DisplayPortCalculator.drawTimeUpdate(time, width * height);
- }
- }
-
- if (layersUpdated && mDrawListener != null) {
- /* Used by robocop for testing purposes */
- mDrawListener.drawFinished();
- }
-
- return mCurrentViewTransform;
- }
-
- /* Invoked by JNI from the compositor thread */
- public ViewTransform syncFrameMetrics(float offsetX, float offsetY, float zoom,
- float cssPageLeft, float cssPageTop, float cssPageRight, float cssPageBottom,
- boolean layersUpdated, int x, int y, int width, int height, float resolution,
- boolean isFirstPaint)
- {
- if (isFirstPaint) {
- setFirstPaintViewport(offsetX, offsetY, zoom,
- cssPageLeft, cssPageTop, cssPageRight, cssPageBottom);
- }
-
- return syncViewportInfo(x, y, width, height, resolution, layersUpdated);
- }
-
- /** This function is invoked by Gecko via JNI; be careful when modifying signature. */
- public LayerRenderer.Frame createFrame() {
- // Create the shaders and textures if necessary.
- if (!mLayerRendererInitialized) {
- mLayerRenderer.checkMonitoringEnabled();
- mLayerRenderer.createDefaultProgram();
- mLayerRendererInitialized = true;
- }
-
- return mLayerRenderer.createFrame(mFrameMetrics);
- }
-
- /** This function is invoked by Gecko via JNI; be careful when modifying signature. */
- public void activateProgram() {
- mLayerRenderer.activateDefaultProgram();
- }
-
- /** This function is invoked by Gecko via JNI; be careful when modifying signature. */
- public void deactivateProgram() {
- mLayerRenderer.deactivateDefaultProgram();
- }
-
- private void geometryChanged(DisplayPortMetrics displayPort) {
- /* Let Gecko know if the screensize has changed */
- sendResizeEventIfNecessary(false);
- if (getRedrawHint()) {
- adjustViewport(displayPort);
- }
- }
-
- /** Implementation of LayerView.Listener */
- @Override
- public void renderRequested() {
- try {
- GeckoAppShell.scheduleComposite();
- } catch (UnsupportedOperationException uoe) {
- // In some very rare cases this gets called before libxul is loaded,
- // so catch and ignore the exception that will throw. See bug 837821
- Log.d(LOGTAG, "Dropping renderRequested call before libxul load.");
- }
- }
-
- /** Implementation of LayerView.Listener */
- @Override
- public void sizeChanged(int width, int height) {
- // We need to make sure a draw happens synchronously at this point,
- // but resizing the surface before the SurfaceView has resized will
- // cause a visible jump.
- mView.getGLController().resumeCompositor(mWindowSize.width, mWindowSize.height);
- }
-
- /** Implementation of LayerView.Listener */
- @Override
- public void surfaceChanged(int width, int height) {
- setViewportSize(width, height);
- }
-
- /** Implementation of PanZoomTarget */
- @Override
- public ImmutableViewportMetrics getViewportMetrics() {
- return mViewportMetrics;
- }
-
- /** Implementation of PanZoomTarget */
- @Override
- public ZoomConstraints getZoomConstraints() {
- return mZoomConstraints;
- }
-
- /** Implementation of PanZoomTarget */
- @Override
- public boolean isFullScreen() {
- return mView.isFullScreen();
- }
-
- /** Implementation of PanZoomTarget */
- @Override
- public RectF getMaxMargins() {
- return mMarginsAnimator.getMaxMargins();
- }
-
- /** Implementation of PanZoomTarget */
- @Override
- public void setAnimationTarget(ImmutableViewportMetrics metrics) {
- if (mGeckoIsReady) {
- // We know what the final viewport of the animation is going to be, so
- // immediately request a draw of that area by setting the display port
- // accordingly. This way we should have the content pre-rendered by the
- // time the animation is done.
- DisplayPortMetrics displayPort = DisplayPortCalculator.calculate(metrics, null);
- adjustViewport(displayPort);
- }
- }
-
- /** Implementation of PanZoomTarget
- * You must hold the monitor while calling this.
- */
- @Override
- public void setViewportMetrics(ImmutableViewportMetrics metrics) {
- setViewportMetrics(metrics, true);
- }
-
- /*
- * You must hold the monitor while calling this.
- */
- private void setViewportMetrics(ImmutableViewportMetrics metrics, boolean notifyGecko) {
- // This class owns the viewport size and the fixed layer margins; don't let other pieces
- // of code clobber either of them. The only place the viewport size should ever be
- // updated is in GeckoLayerClient.setViewportSize, and the only place the margins should
- // ever be updated is in GeckoLayerClient.setFixedLayerMargins; both of these assign to
- // mViewportMetrics directly.
- metrics = metrics.setViewportSize(mViewportMetrics.getWidth(), mViewportMetrics.getHeight());
- metrics = metrics.setMarginsFrom(mViewportMetrics);
- mViewportMetrics = metrics;
-
- viewportMetricsChanged(notifyGecko);
- }
-
- /*
- * You must hold the monitor while calling this.
- */
- private void viewportMetricsChanged(boolean notifyGecko) {
- if (mViewportChangeListener != null) {
- mViewportChangeListener.onMetricsChanged(mViewportMetrics);
- }
-
- mView.requestRender();
- if (notifyGecko && mGeckoIsReady) {
- geometryChanged(null);
- }
- setShadowVisibility();
- }
-
- /*
- * Updates the viewport metrics, overriding the viewport size and margins
- * which are normally retained when calling setViewportMetrics.
- * You must hold the monitor while calling this.
- */
- void forceViewportMetrics(ImmutableViewportMetrics metrics, boolean notifyGecko, boolean forceRedraw) {
- if (forceRedraw) {
- mForceRedraw = true;
- }
- mViewportMetrics = metrics;
- viewportMetricsChanged(notifyGecko);
- }
-
- /** Implementation of PanZoomTarget
- * Scroll the viewport by a certain amount. This will take viewport margins
- * and margin animation into account. If margins are currently animating,
- * this will just go ahead and modify the viewport origin, otherwise the
- * delta will be applied to the margins and the remainder will be applied to
- * the viewport origin.
- *
- * You must hold the monitor while calling this.
- */
- @Override
- public void scrollBy(float dx, float dy) {
- // Set mViewportMetrics manually so the margin changes take.
- mViewportMetrics = mMarginsAnimator.scrollBy(mViewportMetrics, dx, dy);
- viewportMetricsChanged(true);
- }
-
- /** Implementation of PanZoomTarget
- * Notification that a subdocument has been scrolled by a certain amount.
- * This is used here to make sure that the margins are still accessible
- * during subdocument scrolling.
- *
- * You must hold the monitor while calling this.
- */
- @Override
- public void onSubdocumentScrollBy(float dx, float dy) {
- ImmutableViewportMetrics newMarginsMetrics =
- mMarginsAnimator.scrollBy(mViewportMetrics, dx, dy);
- mViewportMetrics = mViewportMetrics.setMarginsFrom(newMarginsMetrics);
- viewportMetricsChanged(true);
- }
-
- /** Implementation of PanZoomTarget */
- @Override
- public void panZoomStopped() {
- if (mViewportChangeListener != null) {
- mViewportChangeListener.onPanZoomStopped();
- }
- }
-
- public interface OnMetricsChangedListener {
- public void onMetricsChanged(ImmutableViewportMetrics viewport);
- public void onPanZoomStopped();
- }
-
- private void setShadowVisibility() {
- ThreadUtils.postToUiThread(new Runnable() {
- @Override
- public void run() {
- if (BrowserApp.mBrowserToolbar == null) {
- return;
- }
- ImmutableViewportMetrics m = mViewportMetrics;
- BrowserApp.mBrowserToolbar.setShadowVisibility(m.viewportRectTop >= m.pageRectTop);
- }
- });
- }
-
- /** Implementation of PanZoomTarget */
- @Override
- public void forceRedraw(DisplayPortMetrics displayPort) {
- mForceRedraw = true;
- if (mGeckoIsReady) {
- geometryChanged(displayPort);
- }
- }
-
- /** Implementation of PanZoomTarget */
- @Override
- public boolean post(Runnable action) {
- return mView.post(action);
- }
-
- /** Implementation of PanZoomTarget */
- @Override
- public boolean postDelayed(Runnable action, long delayMillis) {
- return mView.postDelayed(action, delayMillis);
- }
-
- /** Implementation of PanZoomTarget */
- @Override
- public Object getLock() {
- return this;
- }
-
- /** Implementation of PanZoomTarget
- * Converts a point from layer view coordinates to layer coordinates. In other words, given a
- * point measured in pixels from the top left corner of the layer view, returns the point in
- * pixels measured from the last scroll position we sent to Gecko, in CSS pixels. Assuming the
- * events being sent to Gecko are processed in FIFO order, this calculation should always be
- * correct.
- */
- @Override
- public PointF convertViewPointToLayerPoint(PointF viewPoint) {
- if (!mGeckoIsReady) {
- return null;
- }
-
- ImmutableViewportMetrics viewportMetrics = mViewportMetrics;
- PointF origin = viewportMetrics.getOrigin();
- PointF offset = viewportMetrics.getMarginOffset();
- origin.offset(-offset.x, -offset.y);
- float zoom = viewportMetrics.zoomFactor;
- ImmutableViewportMetrics geckoViewport = mGeckoViewport;
- PointF geckoOrigin = geckoViewport.getOrigin();
- float geckoZoom = geckoViewport.zoomFactor;
-
- // viewPoint + origin - offset gives the coordinate in device pixels from the top-left corner of the page.
- // Divided by zoom, this gives us the coordinate in CSS pixels from the top-left corner of the page.
- // geckoOrigin / geckoZoom is where Gecko thinks it is (scrollTo position) in CSS pixels from
- // the top-left corner of the page. Subtracting the two gives us the offset of the viewPoint from
- // the current Gecko coordinate in CSS pixels.
- PointF layerPoint = new PointF(
- ((viewPoint.x + origin.x) / zoom) - (geckoOrigin.x / geckoZoom),
- ((viewPoint.y + origin.y) / zoom) - (geckoOrigin.y / geckoZoom));
-
- return layerPoint;
- }
-
- public void setOnMetricsChangedListener(OnMetricsChangedListener listener) {
- mViewportChangeListener = listener;
- }
-
- /** Used by robocop for testing purposes. Not for production use! */
- public void setDrawListener(DrawListener listener) {
- mDrawListener = listener;
- }
-
- /** Used by robocop for testing purposes. Not for production use! */
- public static interface DrawListener {
- public void drawFinished();
- }
-}
diff --git a/mobile/android/base/menu/GeckoMenu.java b/mobile/android/base/menu/GeckoMenu.java
deleted file mode 100644
index 025e5bf9f..000000000
--- a/mobile/android/base/menu/GeckoMenu.java
+++ /dev/null
@@ -1,629 +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/. */
-
-package org.mozilla.gecko.menu;
-
-import org.mozilla.gecko.R;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.util.AttributeSet;
-import android.view.ActionProvider;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.SubMenu;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.BaseAdapter;
-import android.widget.LinearLayout;
-import android.widget.ListView;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-public class GeckoMenu extends ListView
- implements Menu,
- AdapterView.OnItemClickListener,
- GeckoMenuItem.OnShowAsActionChangedListener {
- private static final String LOGTAG = "GeckoMenu";
-
- /*
- * A callback for a menu item selected event.
- */
- public static interface Callback {
- // Called when a menu item is selected, with the actual menu item as the argument.
- public boolean onMenuItemSelected(MenuItem item);
- }
-
- /*
- * An interface for a presenter to show the menu.
- * Either an Activity or a View can be a presenter, that can watch for events
- * and show/hide menu.
- */
- public static interface MenuPresenter {
- // Open the menu.
- public void openMenu();
-
- // Show the actual view contaning the menu items. This can either be a parent or sub-menu.
- public void showMenu(View menu);
-
- // Close the menu.
- public void closeMenu();
- }
-
- /*
- * An interface for a presenter of action-items.
- * Either an Activity or a View can be a presenter, that can watch for events
- * and add/remove action-items. If not ActionItemBarPresenter, the menu uses a
- * DefaultActionItemBar, that shows the action-items as a header over list-view.
- */
- public static interface ActionItemBarPresenter {
- // Add an action-item.
- public void addActionItem(View actionItem);
-
- // Remove an action-item.
- public void removeActionItem(View actionItem);
- }
-
- protected static final int NO_ID = 0;
-
- // List of all menu items.
- private List<GeckoMenuItem> mItems;
-
- // Map of items in action-bar and their views.
- private Map<GeckoMenuItem, View> mActionItems;
-
- // Reference to a callback for menu events.
- private Callback mCallback;
-
- // Reference to menu presenter.
- private MenuPresenter mMenuPresenter;
-
- // Reference to action-items bar in action-bar.
- private ActionItemBarPresenter mActionItemBarPresenter;
-
- // Adapter to hold the list of menu items.
- private MenuItemsAdapter mAdapter;
-
- public GeckoMenu(Context context) {
- this(context, null);
- }
-
- public GeckoMenu(Context context, AttributeSet attrs) {
- this(context, attrs, android.R.attr.listViewStyle);
- }
-
- public GeckoMenu(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
-
- setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
- LayoutParams.FILL_PARENT));
-
- // Attach an adapter.
- mAdapter = new MenuItemsAdapter();
- setAdapter(mAdapter);
- setOnItemClickListener(this);
-
- mItems = new ArrayList<GeckoMenuItem>();
- mActionItems = new HashMap<GeckoMenuItem, View>();
-
- mActionItemBarPresenter = (DefaultActionItemBar) LayoutInflater.from(context).inflate(R.layout.menu_action_bar, null);
- }
-
- @Override
- public MenuItem add(CharSequence title) {
- GeckoMenuItem menuItem = new GeckoMenuItem(this, NO_ID, 0, title);
- addItem(menuItem);
- return menuItem;
- }
-
- @Override
- public MenuItem add(int groupId, int itemId, int order, int titleRes) {
- GeckoMenuItem menuItem = new GeckoMenuItem(this, itemId, order, titleRes);
- addItem(menuItem);
- return menuItem;
- }
-
- @Override
- public MenuItem add(int titleRes) {
- GeckoMenuItem menuItem = new GeckoMenuItem(this, NO_ID, 0, titleRes);
- addItem(menuItem);
- return menuItem;
- }
-
- @Override
- public MenuItem add(int groupId, int itemId, int order, CharSequence title) {
- GeckoMenuItem menuItem = new GeckoMenuItem(this, itemId, order, title);
- addItem(menuItem);
- return menuItem;
- }
-
- private void addItem(GeckoMenuItem menuItem) {
- menuItem.setOnShowAsActionChangedListener(this);
- mAdapter.addMenuItem(menuItem);
- mItems.add(menuItem);
- }
-
- private void addActionItem(final GeckoMenuItem menuItem) {
- menuItem.setOnShowAsActionChangedListener(this);
-
- if (mActionItems.size() == 0 &&
- mActionItemBarPresenter instanceof DefaultActionItemBar) {
- // Reset the adapter before adding the header view to a list.
- setAdapter(null);
- addHeaderView((DefaultActionItemBar) mActionItemBarPresenter);
- setAdapter(mAdapter);
- }
-
- View actionView = menuItem.getActionView();
- actionView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- handleMenuItemClick(menuItem);
- }
- });
-
- mActionItems.put(menuItem, actionView);
- mActionItemBarPresenter.addActionItem(actionView);
- mItems.add(menuItem);
- }
-
- @Override
- public int addIntentOptions(int groupId, int itemId, int order, ComponentName caller, Intent[] specifics, Intent intent, int flags, MenuItem[] outSpecificItems) {
- return 0;
- }
-
- @Override
- public SubMenu addSubMenu(int groupId, int itemId, int order, CharSequence title) {
- MenuItem menuItem = add(groupId, itemId, order, title);
- return addSubMenu(menuItem);
- }
-
- @Override
- public SubMenu addSubMenu(int groupId, int itemId, int order, int titleRes) {
- MenuItem menuItem = add(groupId, itemId, order, titleRes);
- return addSubMenu(menuItem);
- }
-
- @Override
- public SubMenu addSubMenu(CharSequence title) {
- MenuItem menuItem = add(title);
- return addSubMenu(menuItem);
- }
-
- @Override
- public SubMenu addSubMenu(int titleRes) {
- MenuItem menuItem = add(titleRes);
- return addSubMenu(menuItem);
- }
-
- private SubMenu addSubMenu(MenuItem menuItem) {
- GeckoSubMenu subMenu = new GeckoSubMenu(getContext());
- subMenu.setMenuItem(menuItem);
- subMenu.setCallback(mCallback);
- subMenu.setMenuPresenter(mMenuPresenter);
- ((GeckoMenuItem) menuItem).setSubMenu(subMenu);
- return subMenu;
- }
-
- @Override
- public void clear() {
- for (GeckoMenuItem menuItem : mItems) {
- if (menuItem.hasSubMenu()) {
- menuItem.getSubMenu().clear();
- }
- }
-
- mAdapter.clear();
-
- mItems.clear();
- mActionItems.clear();
- }
-
- @Override
- public void close() {
- if (mMenuPresenter != null)
- mMenuPresenter.closeMenu();
- }
-
- private void showMenu(View viewForMenu) {
- if (mMenuPresenter != null)
- mMenuPresenter.showMenu(viewForMenu);
- }
-
- @Override
- public MenuItem findItem(int id) {
- for (GeckoMenuItem menuItem : mItems) {
- if (menuItem.getItemId() == id) {
- return menuItem;
- } else if (menuItem.hasSubMenu()) {
- if (!menuItem.hasActionProvider()) {
- SubMenu subMenu = menuItem.getSubMenu();
- MenuItem item = subMenu.findItem(id);
- if (item != null)
- return item;
- }
- }
- }
- return null;
- }
-
- @Override
- public MenuItem getItem(int index) {
- if (index < mItems.size())
- return mItems.get(index);
-
- return null;
- }
-
- @Override
- public boolean hasVisibleItems() {
- for (GeckoMenuItem menuItem : mItems) {
- if (menuItem.isVisible())
- return true;
- }
-
- return false;
- }
-
- @Override
- public boolean isShortcutKey(int keyCode, KeyEvent event) {
- return true;
- }
-
- @Override
- public boolean performIdentifierAction(int id, int flags) {
- return false;
- }
-
- @Override
- public boolean performShortcut(int keyCode, KeyEvent event, int flags) {
- return false;
- }
-
- @Override
- public void removeGroup(int groupId) {
- }
-
- @Override
- public void removeItem(int id) {
- GeckoMenuItem item = (GeckoMenuItem) findItem(id);
- if (item == null)
- return;
-
- if (mActionItems.containsKey(item)) {
- if (mActionItemBarPresenter != null)
- mActionItemBarPresenter.removeActionItem(mActionItems.get(item));
-
- mActionItems.remove(item);
- mItems.remove(item);
-
- if (mActionItems.size() == 0 &&
- mActionItemBarPresenter instanceof DefaultActionItemBar) {
- // Reset the adapter before removing the header view from a list.
- setAdapter(null);
- removeHeaderView((DefaultActionItemBar) mActionItemBarPresenter);
- setAdapter(mAdapter);
- }
-
- return;
- }
-
- mAdapter.removeMenuItem(item);
- mItems.remove(item);
- }
-
- @Override
- public void setGroupCheckable(int group, boolean checkable, boolean exclusive) {
- }
-
- @Override
- public void setGroupEnabled(int group, boolean enabled) {
- }
-
- @Override
- public void setGroupVisible(int group, boolean visible) {
- }
-
- @Override
- public void setQwertyMode(boolean isQwerty) {
- }
-
- @Override
- public int size() {
- return mItems.size();
- }
-
- @Override
- public boolean hasActionItemBar() {
- return (mActionItemBarPresenter != null);
- }
-
- @Override
- public void onShowAsActionChanged(GeckoMenuItem item, boolean isActionItem) {
- removeItem(item.getItemId());
-
- if (isActionItem)
- addActionItem(item);
- else
- addItem(item);
- }
-
- public void onItemChanged(GeckoMenuItem item) {
- if (item.isActionItem()) {
- final MenuItemActionBar actionView = (MenuItemActionBar) mActionItems.get(item);
- if (actionView != null) {
- // The update could be coming from the background thread.
- // Post a runnable on the UI thread of the view for it to update.
- final GeckoMenuItem menuItem = item;
- actionView.post(new Runnable() {
- @Override
- public void run() {
- if (menuItem.isVisible()) {
- actionView.setVisibility(View.VISIBLE);
- actionView.initialize(menuItem);
- } else {
- actionView.setVisibility(View.GONE);
- }
- }
- });
- }
- } else {
- mAdapter.notifyDataSetChanged();
- }
- }
-
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- // We might be showing headers. Account them while using the position.
- position -= getHeaderViewsCount();
-
- GeckoMenuItem item = mAdapter.getItem(position);
- handleMenuItemClick(item);
- }
-
- private void handleMenuItemClick(GeckoMenuItem item) {
- if (!item.isEnabled())
- return;
-
- if (item.invoke()) {
- close();
- } else if (item.hasSubMenu()) {
- // Refresh the submenu for the provider.
- ActionProvider provider = item.getActionProvider();
- if (provider != null) {
- GeckoSubMenu subMenu = new GeckoSubMenu(getContext());
- provider.onPrepareSubMenu(subMenu);
- item.setSubMenu(subMenu);
- }
-
- // Show the submenu.
- GeckoSubMenu subMenu = (GeckoSubMenu) item.getSubMenu();
- showMenu(subMenu);
- } else {
- close();
- mCallback.onMenuItemSelected(item);
- }
- }
-
- public Callback getCallback() {
- return mCallback;
- }
-
- public MenuPresenter getMenuPresenter() {
- return mMenuPresenter;
- }
-
- public void setCallback(Callback callback) {
- mCallback = callback;
-
- // Update the submenus just in case this changes on the fly.
- for (GeckoMenuItem menuItem : mItems) {
- if (menuItem.hasSubMenu()) {
- GeckoSubMenu subMenu = (GeckoSubMenu) menuItem.getSubMenu();
- subMenu.setCallback(mCallback);
- }
- }
- }
-
- public void setMenuPresenter(MenuPresenter presenter) {
- mMenuPresenter = presenter;
-
- // Update the submenus just in case this changes on the fly.
- for (GeckoMenuItem menuItem : mItems) {
- if (menuItem.hasSubMenu()) {
- GeckoSubMenu subMenu = (GeckoSubMenu) menuItem.getSubMenu();
- subMenu.setMenuPresenter(mMenuPresenter);
- }
- }
- }
-
- public void setActionItemBarPresenter(ActionItemBarPresenter presenter) {
- mActionItemBarPresenter = presenter;
- }
-
- // Action Items are added to the header view by default.
- // URL bar can register itself as a presenter, in case it has a different place to show them.
- public static class DefaultActionItemBar extends LinearLayout
- implements ActionItemBarPresenter {
- public DefaultActionItemBar(Context context) {
- super(context);
- }
-
- public DefaultActionItemBar(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- @Override
- public void addActionItem(View actionItem) {
- LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(actionItem.getLayoutParams());
- params.weight = 1.0f;
- actionItem.setLayoutParams(params);
- addView(actionItem);
- }
-
- @Override
- public void removeActionItem(View actionItem) {
- removeView(actionItem);
- }
- }
-
- // Adapter to bind menu items to the list.
- private class MenuItemsAdapter extends BaseAdapter {
- private static final int VIEW_TYPE_DEFAULT = 0;
- private static final int VIEW_TYPE_ACTION_MODE = 1;
-
- private List<GeckoMenuItem> mItems;
-
- public MenuItemsAdapter() {
- mItems = new ArrayList<GeckoMenuItem>();
- }
-
- @Override
- public int getCount() {
- if (mItems == null)
- return 0;
-
- int visibleCount = 0;
- for (GeckoMenuItem item : mItems) {
- if (item.isVisible())
- visibleCount++;
- }
-
- return visibleCount;
- }
-
- @Override
- public GeckoMenuItem getItem(int position) {
- for (GeckoMenuItem item : mItems) {
- if (item.isVisible()) {
- position--;
-
- if (position < 0)
- return item;
- }
- }
-
- return null;
- }
-
- @Override
- public long getItemId(int position) {
- return position;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- GeckoMenuItem item = getItem(position);
- GeckoMenuItem.Layout view = null;
-
- // Try to re-use the view.
- if (convertView == null && getItemViewType(position) == VIEW_TYPE_DEFAULT) {
- view = new MenuItemDefault(parent.getContext(), null);
- } else {
- view = (GeckoMenuItem.Layout) convertView;
- }
-
- if (view == null || view instanceof MenuItemActionView) {
- // Always get from the menu item.
- // This will ensure that the default activity is refreshed.
- view = (MenuItemActionView) item.getActionView();
-
- // ListView will not perform an item click if the row has a focusable view in it.
- // Hence, forward the click event on the menu item in the action-view to the ListView.
- final View actionView = (View) view;
- final int pos = position;
- final long id = getItemId(position);
- ((MenuItemActionView) view).setMenuItemClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- GeckoMenu listView = GeckoMenu.this;
- listView.performItemClick(actionView, pos + listView.getHeaderViewsCount(), id);
- }
- });
- }
-
- // Initialize the view.
- view.initialize(item);
- return (View) view;
- }
-
- @Override
- public int getItemViewType(int position) {
- return getItem(position).getActionProvider() == null ? VIEW_TYPE_DEFAULT : VIEW_TYPE_ACTION_MODE;
- }
-
- @Override
- public int getViewTypeCount() {
- return 2;
- }
-
- @Override
- public boolean hasStableIds() {
- return false;
- }
-
- @Override
- public boolean areAllItemsEnabled() {
- for (GeckoMenuItem item : mItems) {
- if (!item.isEnabled())
- return false;
- }
-
- return true;
- }
-
- @Override
- public boolean isEnabled(int position) {
- return getItem(position).isEnabled();
- }
-
- public void addMenuItem(GeckoMenuItem menuItem) {
- if (mItems.contains(menuItem))
- return;
-
- // Insert it in proper order.
- int index = 0;
- for (GeckoMenuItem item : mItems) {
- if (item.getOrder() > menuItem.getOrder()) {
- mItems.add(index, menuItem);
- notifyDataSetChanged();
- return;
- } else {
- index++;
- }
- }
-
- // Add the menuItem at the end.
- mItems.add(menuItem);
- notifyDataSetChanged();
- }
-
- public void removeMenuItem(GeckoMenuItem menuItem) {
- // Remove it from the list.
- mItems.remove(menuItem);
- notifyDataSetChanged();
- }
-
- public void clear() {
- mItems.clear();
- notifyDataSetChanged();
- }
-
- public GeckoMenuItem getMenuItem(int id) {
- for (GeckoMenuItem item : mItems) {
- if (item.getItemId() == id)
- return item;
- }
-
- return null;
- }
- }
-}
diff --git a/mobile/android/base/menu/GeckoMenuInflater.java b/mobile/android/base/menu/GeckoMenuInflater.java
deleted file mode 100644
index 9c2b52d68..000000000
--- a/mobile/android/base/menu/GeckoMenuInflater.java
+++ /dev/null
@@ -1,158 +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/. */
-
-package org.mozilla.gecko.menu;
-
-import org.mozilla.gecko.R;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.content.res.XmlResourceParser;
-import android.os.Build;
-import android.util.AttributeSet;
-import android.util.Xml;
-import android.view.InflateException;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.SubMenu;
-
-import java.io.IOException;
-
-public class GeckoMenuInflater extends MenuInflater {
- private static final String LOGTAG = "GeckoMenuInflater";
-
- private static final String TAG_MENU = "menu";
- private static final String TAG_ITEM = "item";
- private static final int NO_ID = 0;
-
- private Context mContext;
-
- private boolean isSubMenu;
-
- // Private class to hold the parsed menu item.
- private class ParsedItem {
- public int id;
- public int order;
- public CharSequence title;
- public int iconRes;
- public boolean checkable;
- public boolean checked;
- public boolean visible;
- public boolean enabled;
- public int showAsAction;
- }
-
- public GeckoMenuInflater(Context context) {
- super(context);
- mContext = context;
-
- isSubMenu = false;
- }
-
- @Override
- public void inflate(int menuRes, Menu menu) {
-
- // This does not check for a well-formed XML.
-
- XmlResourceParser parser = null;
- try {
- parser = mContext.getResources().getXml(menuRes);
- AttributeSet attrs = Xml.asAttributeSet(parser);
-
- ParsedItem item = null;
- SubMenu subMenu = null;
- MenuItem menuItem = null;
-
- String tag;
- int eventType = parser.getEventType();
-
- do {
- tag = parser.getName();
-
- switch (eventType) {
- case XmlPullParser.START_TAG:
- if (tag.equals(TAG_ITEM)) {
- // Parse the menu item.
- item = new ParsedItem();
- parseItem(item, attrs);
- } else if (tag.equals(TAG_MENU)) {
- if (item != null) {
- // Start parsing the sub menu.
- isSubMenu = true;
- subMenu = menu.addSubMenu(NO_ID, item.id, item.order, item.title);
- menuItem = subMenu.getItem();
-
- // Set the menu item in main menu.
- setValues(item, menuItem);
- }
- }
- break;
-
- case XmlPullParser.END_TAG:
- if (parser.getName().equals(TAG_ITEM)) {
- if (isSubMenu && subMenu == null) {
- isSubMenu = false;
- } else {
- // Add the item.
- if (subMenu == null)
- menuItem = menu.add(NO_ID, item.id, item.order, item.title);
- else
- menuItem = subMenu.add(NO_ID, item.id, item.order, item.title);
-
- setValues(item, menuItem);
- }
- } else if (tag.equals(TAG_MENU)) {
- // End of sub menu.
- subMenu = null;
- }
- break;
- }
-
- eventType = parser.next();
-
- } while (eventType != XmlPullParser.END_DOCUMENT);
-
- } catch (XmlPullParserException e) {
- throw new InflateException("Error inflating menu XML", e);
- } catch (IOException e) {
- throw new InflateException("Error inflating menu XML", e);
- } finally {
- if (parser != null)
- parser.close();
- }
- }
-
- public void parseItem(ParsedItem item, AttributeSet attrs) {
- TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.MenuItem);
-
- item.id = a.getResourceId(R.styleable.MenuItem_android_id, NO_ID);
- item.order = a.getInt(R.styleable.MenuItem_android_orderInCategory, 0);
- item.title = a.getText(R.styleable.MenuItem_android_title);
- item.iconRes = a.getResourceId(R.styleable.MenuItem_android_icon, 0);
- item.checkable = a.getBoolean(R.styleable.MenuItem_android_checkable, false);
- item.checked = a.getBoolean(R.styleable.MenuItem_android_checked, false);
- item.visible = a.getBoolean(R.styleable.MenuItem_android_visible, true);
- item.enabled = a.getBoolean(R.styleable.MenuItem_android_enabled, true);
-
- if (Build.VERSION.SDK_INT >= 11)
- item.showAsAction = a.getInt(R.styleable.MenuItem_android_showAsAction, 0);
-
- a.recycle();
- }
-
- public void setValues(ParsedItem item, MenuItem menuItem) {
- menuItem.setChecked(item.checked)
- .setVisible(item.visible)
- .setEnabled(item.enabled)
- .setCheckable(item.checkable)
- .setIcon(item.iconRes);
-
- if (Build.VERSION.SDK_INT >= 11)
- menuItem.setShowAsAction(item.showAsAction);
- }
-}
diff --git a/mobile/android/base/menu/GeckoMenuItem.java b/mobile/android/base/menu/GeckoMenuItem.java
deleted file mode 100644
index 44d1e4b19..000000000
--- a/mobile/android/base/menu/GeckoMenuItem.java
+++ /dev/null
@@ -1,357 +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/. */
-
-package org.mozilla.gecko.menu;
-
-import org.mozilla.gecko.widget.GeckoActionProvider;
-
-import android.content.Intent;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.view.ActionProvider;
-import android.view.ContextMenu;
-import android.view.MenuItem;
-import android.view.SubMenu;
-import android.view.View;
-
-public class GeckoMenuItem implements MenuItem {
- private static final String LOGTAG = "GeckoMenuItem";
-
- // A View that can show a MenuItem should be able to initialize from
- // the properties of the MenuItem.
- public static interface Layout {
- public void initialize(GeckoMenuItem item);
- }
-
- public static interface OnShowAsActionChangedListener {
- public boolean hasActionItemBar();
- public void onShowAsActionChanged(GeckoMenuItem item, boolean isActionItem);
- }
-
- private int mId;
- private int mOrder;
- private View mActionView;
- private boolean mActionItem = false;
- private CharSequence mTitle;
- private CharSequence mTitleCondensed;
- private boolean mCheckable = false;
- private boolean mChecked = false;
- private boolean mVisible = true;
- private boolean mEnabled = true;
- private Drawable mIcon;
- private int mIconRes;
- private ActionProvider mActionProvider;
- private GeckoMenu mMenu;
- private GeckoSubMenu mSubMenu;
- private MenuItem.OnMenuItemClickListener mMenuItemClickListener = null;
- private OnShowAsActionChangedListener mShowAsActionChangedListener;
-
- public GeckoMenuItem(GeckoMenu menu, int id, int order, int titleRes) {
- mMenu = menu;
- mId = id;
- mOrder = order;
- setTitle(titleRes);
- }
-
- public GeckoMenuItem(GeckoMenu menu, int id, int order, CharSequence title) {
- mMenu = menu;
- mId = id;
- mOrder = order;
- setTitle(title);
- }
-
- @Override
- public boolean collapseActionView() {
- return false;
- }
-
- @Override
- public boolean expandActionView() {
- return false;
- }
-
- public boolean hasActionProvider() {
- if (Build.VERSION.SDK_INT < 14) {
- return false;
- }
-
- return (mActionProvider != null);
- }
-
- @Override
- public ActionProvider getActionProvider() {
- return mActionProvider;
- }
-
- @Override
- public View getActionView() {
- if (mActionProvider != null && mActionProvider instanceof GeckoActionProvider) {
- return ((GeckoActionProvider) mActionProvider).getView();
- }
-
- return mActionView;
- }
-
- @Override
- public char getAlphabeticShortcut() {
- return 0;
- }
-
- @Override
- public int getGroupId() {
- return 0;
- }
-
- @Override
- public Drawable getIcon() {
- if (mIcon == null) {
- if (mIconRes != 0)
- return mMenu.getResources().getDrawable(mIconRes);
- else
- return null;
- } else {
- return mIcon;
- }
- }
-
- @Override
- public Intent getIntent() {
- return null;
- }
-
- @Override
- public int getItemId() {
- return mId;
- }
-
- @Override
- public ContextMenu.ContextMenuInfo getMenuInfo() {
- return null;
- }
-
- @Override
- public char getNumericShortcut() {
- return 0;
- }
-
- @Override
- public int getOrder() {
- return mOrder;
- }
-
- @Override
- public SubMenu getSubMenu() {
- return mSubMenu;
- }
-
- @Override
- public CharSequence getTitle() {
- return mTitle;
- }
-
- @Override
- public CharSequence getTitleCondensed() {
- return mTitleCondensed;
- }
-
- @Override
- public boolean hasSubMenu() {
- if (mActionProvider != null)
- return mActionProvider.hasSubMenu();
-
- return (mSubMenu != null);
- }
-
- public boolean isActionItem() {
- return mActionItem;
- }
-
- @Override
- public boolean isActionViewExpanded() {
- return false;
- }
-
- @Override
- public boolean isCheckable() {
- return mCheckable;
- }
-
- @Override
- public boolean isChecked() {
- return mChecked;
- }
-
- @Override
- public boolean isEnabled() {
- return mEnabled;
- }
-
- @Override
- public boolean isVisible() {
- return mVisible;
- }
-
- @Override
- public MenuItem setActionProvider(ActionProvider actionProvider) {
- mActionProvider = actionProvider;
- if (mActionProvider != null && mActionProvider instanceof GeckoActionProvider) {
- GeckoActionProvider provider = (GeckoActionProvider) mActionProvider;
- provider.setOnTargetSelectedListener(new GeckoActionProvider.OnTargetSelectedListener() {
- @Override
- public void onTargetSelected() {
- mMenu.close();
- }
- });
- }
-
- return this;
- }
-
- @Override
- public MenuItem setActionView(int resId) {
- return this;
- }
-
- @Override
- public MenuItem setActionView(View view) {
- return this;
- }
-
- @Override
- public MenuItem setAlphabeticShortcut(char alphaChar) {
- return this;
- }
-
- @Override
- public MenuItem setCheckable(boolean checkable) {
- mCheckable = checkable;
- mMenu.onItemChanged(this);
- return this;
- }
-
- @Override
- public MenuItem setChecked(boolean checked) {
- mChecked = checked;
- mMenu.onItemChanged(this);
- return this;
- }
-
- @Override
- public MenuItem setEnabled(boolean enabled) {
- mEnabled = enabled;
- mMenu.onItemChanged(this);
- return this;
- }
-
- @Override
- public MenuItem setIcon(Drawable icon) {
- mIcon = icon;
- mMenu.onItemChanged(this);
- return this;
- }
-
- @Override
- public MenuItem setIcon(int iconRes) {
- mIconRes = iconRes;
- mMenu.onItemChanged(this);
- return this;
- }
-
- @Override
- public MenuItem setIntent(Intent intent) {
- return this;
- }
-
- @Override
- public MenuItem setNumericShortcut(char numericChar) {
- return this;
- }
-
- @Override
- public MenuItem setOnActionExpandListener(MenuItem.OnActionExpandListener listener) {
- return this;
- }
-
- @Override
- public MenuItem setOnMenuItemClickListener(MenuItem.OnMenuItemClickListener menuItemClickListener) {
- mMenuItemClickListener = menuItemClickListener;
- return this;
- }
-
- @Override
- public MenuItem setShortcut(char numericChar, char alphaChar) {
- return this;
- }
-
- @Override
- public void setShowAsAction(int actionEnum) {
- if (mShowAsActionChangedListener == null)
- return;
-
- if (mActionItem == (actionEnum > 0))
- return;
-
- if (actionEnum > 0) {
- if (!mShowAsActionChangedListener.hasActionItemBar())
- return;
-
- // Change the type to just an icon
- MenuItemActionBar actionView = new MenuItemActionBar(mMenu.getContext(), null);
- actionView.initialize(this);
- mActionView = actionView;
-
- mActionItem = (actionEnum > 0);
- }
-
- mShowAsActionChangedListener.onShowAsActionChanged(this, mActionItem);
- }
-
- @Override
- public MenuItem setShowAsActionFlags(int actionEnum) {
- return this;
- }
-
- public MenuItem setSubMenu(GeckoSubMenu subMenu) {
- mSubMenu = subMenu;
- return this;
- }
-
- @Override
- public MenuItem setTitle(CharSequence title) {
- mTitle = title;
- mMenu.onItemChanged(this);
- return this;
- }
-
- @Override
- public MenuItem setTitle(int title) {
- mTitle = mMenu.getResources().getString(title);
- mMenu.onItemChanged(this);
- return this;
- }
-
- @Override
- public MenuItem setTitleCondensed(CharSequence title) {
- mTitleCondensed = title;
- return this;
- }
-
- @Override
- public MenuItem setVisible(boolean visible) {
- mVisible = visible;
- mMenu.onItemChanged(this);
- return this;
- }
-
- public boolean invoke() {
- if (mMenuItemClickListener != null)
- return mMenuItemClickListener.onMenuItemClick(this);
- else
- return false;
- }
-
- public void setOnShowAsActionChangedListener(OnShowAsActionChangedListener listener) {
- mShowAsActionChangedListener = listener;
- }
-}
diff --git a/mobile/android/base/menu/GeckoSubMenu.java b/mobile/android/base/menu/GeckoSubMenu.java
deleted file mode 100644
index 554cdd177..000000000
--- a/mobile/android/base/menu/GeckoSubMenu.java
+++ /dev/null
@@ -1,81 +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/. */
-
-package org.mozilla.gecko.menu;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.view.MenuItem;
-import android.view.SubMenu;
-import android.view.View;
-
-public class GeckoSubMenu extends GeckoMenu
- implements SubMenu {
- private static final String LOGTAG = "GeckoSubMenu";
-
- // MenuItem associated with this submenu.
- private MenuItem mMenuItem;
-
- public GeckoSubMenu(Context context) {
- super(context);
- }
-
- public GeckoSubMenu(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public GeckoSubMenu(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
-
- @Override
- public void clearHeader() {
- }
-
- public SubMenu setMenuItem(MenuItem item) {
- mMenuItem = item;
- return this;
- }
-
- @Override
- public MenuItem getItem() {
- return mMenuItem;
- }
-
- @Override
- public SubMenu setHeaderIcon(Drawable icon) {
- return this;
- }
-
- @Override
- public SubMenu setHeaderIcon(int iconRes) {
- return this;
- }
-
- @Override
- public SubMenu setHeaderTitle(CharSequence title) {
- return this;
- }
-
- @Override
- public SubMenu setHeaderTitle(int titleRes) {
- return this;
- }
-
- @Override
- public SubMenu setHeaderView(View view) {
- return this;
- }
-
- @Override
- public SubMenu setIcon(Drawable icon) {
- return this;
- }
-
- @Override
- public SubMenu setIcon(int iconRes) {
- return this;
- }
-}
diff --git a/mobile/android/base/mozglue/GeckoLoader.java.in b/mobile/android/base/mozglue/GeckoLoader.java.in
deleted file mode 100644
index 575faea76..000000000
--- a/mobile/android/base/mozglue/GeckoLoader.java.in
+++ /dev/null
@@ -1,284 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; 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.gecko.mozglue;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Build;
-import android.os.Environment;
-import android.util.Log;
-
-import java.io.File;
-import java.text.DecimalFormat;
-import java.text.DecimalFormatSymbols;
-import java.text.NumberFormat;
-import java.util.Locale;
-
-public final class GeckoLoader {
- private static final String LOGTAG = "GeckoLoader";
-
- private static File sCacheFile;
- private static File sGREDir;
-
- private static final Object sLibLoadingLock = new Object();
- // Must hold sLibLoadingLock while accessing the following boolean variables.
- private static boolean sSQLiteLibsLoaded;
- private static boolean sNSSLibsLoaded;
- private static boolean sMozGlueLoaded;
- private static boolean sLibsSetup;
-
- private GeckoLoader() {
- // prevent instantiation
- }
-
- public static File getCacheDir(Context context) {
- if (sCacheFile == null) {
- sCacheFile = context.getCacheDir();
- }
- return sCacheFile;
- }
-
- public static File getGREDir(Context context) {
- if (sGREDir == null) {
- sGREDir = new File(context.getApplicationInfo().dataDir);
- }
- return sGREDir;
- }
-
- private static void setupPluginEnvironment(Context context, String[] pluginDirs) {
- // setup plugin path directories
- try {
- // Check to see if plugins were blocked.
- if (pluginDirs == null) {
- putenv("MOZ_PLUGINS_BLOCKED=1");
- putenv("MOZ_PLUGIN_PATH=");
- return;
- }
-
- StringBuffer pluginSearchPath = new StringBuffer();
- for (int i = 0; i < pluginDirs.length; i++) {
- pluginSearchPath.append(pluginDirs[i]);
- pluginSearchPath.append(":");
- }
- putenv("MOZ_PLUGIN_PATH="+pluginSearchPath);
-
- File pluginDataDir = context.getDir("plugins", 0);
- putenv("ANDROID_PLUGIN_DATADIR=" + pluginDataDir.getPath());
-
- File pluginPrivateDataDir = context.getDir("plugins_private", 0);
- putenv("ANDROID_PLUGIN_DATADIR_PRIVATE=" + pluginPrivateDataDir.getPath());
-
- } catch (Exception ex) {
- Log.w(LOGTAG, "Caught exception getting plugin dirs.", ex);
- }
- }
-
- private static void setupDownloadEnvironment(Context context) {
- try {
- File downloadDir = null;
- File updatesDir = null;
- if (Build.VERSION.SDK_INT >= 8) {
- downloadDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
- updatesDir = context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS);
- }
- if (downloadDir == null) {
- downloadDir = new File(Environment.getExternalStorageDirectory().getPath(), "download");
- }
- if (updatesDir == null) {
- updatesDir = downloadDir;
- }
- putenv("DOWNLOADS_DIRECTORY=" + downloadDir.getPath());
- putenv("UPDATES_DIRECTORY=" + updatesDir.getPath());
- }
- catch (Exception e) {
- Log.w(LOGTAG, "No download directory found.", e);
- }
- }
-
- private static void delTree(File file) {
- if (file.isDirectory()) {
- File children[] = file.listFiles();
- for (File child : children) {
- delTree(child);
- }
- }
- file.delete();
- }
-
- private static File getTmpDir(Context context) {
- File tmpDir = context.getDir("tmpdir", Context.MODE_PRIVATE);
- // check if the old tmp dir is there
- File oldDir = new File(tmpDir.getParentFile(), "app_tmp");
- if (oldDir.exists()) {
- delTree(oldDir);
- }
- return tmpDir;
- }
-
- public static void setupGeckoEnvironment(Activity context, String[] pluginDirs, String profilePath) {
- // if we have an intent (we're being launched by an activity)
- // read in any environmental variables from it here
- Intent intent = context.getIntent();
- if (intent != null) {
- String env = intent.getStringExtra("env0");
- Log.d(LOGTAG, "Gecko environment env0: " + env);
- for (int c = 1; env != null; c++) {
- putenv(env);
- env = intent.getStringExtra("env" + c);
- Log.d(LOGTAG, "env" + c + ": " + env);
- }
- }
-
- setupPluginEnvironment(context, pluginDirs);
- setupDownloadEnvironment(context);
-
- // profile home path
- putenv("HOME=" + profilePath);
-
- // setup the tmp path
- File f = getTmpDir(context);
- if (!f.exists()) {
- f.mkdirs();
- }
- putenv("TMPDIR=" + f.getPath());
-
- // setup the downloads path
- f = Environment.getDownloadCacheDirectory();
- putenv("EXTERNAL_STORAGE=" + f.getPath());
-
- // setup the app-specific cache path
- f = context.getCacheDir();
- putenv("CACHE_DIRECTORY=" + f.getPath());
-
- /* We really want to use this code, but it requires bumping up the SDK to 17 so for now
- we will use reflection. See https://bugzilla.mozilla.org/show_bug.cgi?id=811763#c11
-
- if (Build.VERSION.SDK_INT >= 17) {
- android.os.UserManager um = (android.os.UserManager)context.getSystemService(Context.USER_SERVICE);
- if (um != null) {
- putenv("MOZ_ANDROID_USER_SERIAL_NUMBER=" + um.getSerialNumberForUser(android.os.Process.myUserHandle()));
- } else {
- Log.d(LOGTAG, "Unable to obtain user manager service on a device with SDK version " + Build.VERSION.SDK_INT);
- }
- }
- */
- try {
- Object userManager = context.getSystemService("user");
- if (userManager != null) {
- // if userManager is non-null that means we're running on 4.2+ and so the rest of this
- // should just work
- Object userHandle = android.os.Process.class.getMethod("myUserHandle", (Class[])null).invoke(null);
- Object userSerial = userManager.getClass().getMethod("getSerialNumberForUser", userHandle.getClass()).invoke(userManager, userHandle);
- putenv("MOZ_ANDROID_USER_SERIAL_NUMBER=" + userSerial.toString());
- }
- } catch (Exception e) {
- // Guard against any unexpected failures
- Log.d(LOGTAG, "Unable to set the user serial number", e);
- }
-
- setupLocaleEnvironment();
- }
-
- private static void loadLibsSetup(Context context) {
- synchronized (sLibLoadingLock) {
- if (sLibsSetup) {
- return;
- }
- sLibsSetup = true;
- }
-
- // The package data lib directory isn't placed in ld.so's
- // search path, so we have to manually load libraries that
- // libxul will depend on. Not ideal.
-
- File cacheFile = getCacheDir(context);
- putenv("GRE_HOME=" + getGREDir(context).getPath());
-
- // setup the libs cache
- String linkerCache = System.getenv("MOZ_LINKER_CACHE");
- if (linkerCache == null) {
- linkerCache = cacheFile.getPath();
- putenv("MOZ_LINKER_CACHE=" + linkerCache);
- }
-
-#ifdef MOZ_LINKER_EXTRACT
- putenv("MOZ_LINKER_EXTRACT=1");
- // Ensure that the cache dir is world-writable
- File cacheDir = new File(linkerCache);
- if (cacheDir.isDirectory()) {
- cacheDir.setWritable(true, false);
- cacheDir.setExecutable(true, false);
- cacheDir.setReadable(true, false);
- }
-#endif
- }
-
- public static void loadSQLiteLibs(Context context, String apkName) {
- synchronized (sLibLoadingLock) {
- if (sSQLiteLibsLoaded) {
- return;
- }
- sSQLiteLibsLoaded = true;
- }
-
- loadMozGlue(context);
- // the extract libs parameter is being removed in bug 732069
- loadLibsSetup(context);
- loadSQLiteLibsNative(apkName, false);
- }
-
- public static void loadNSSLibs(Context context, String apkName) {
- synchronized (sLibLoadingLock) {
- if (sNSSLibsLoaded) {
- return;
- }
- sNSSLibsLoaded = true;
- }
-
- loadMozGlue(context);
- loadLibsSetup(context);
- loadNSSLibsNative(apkName, false);
- }
-
- public static void loadMozGlue(Context context) {
- synchronized (sLibLoadingLock) {
- if (sMozGlueLoaded) {
- return;
- }
- sMozGlueLoaded = true;
- }
-
- System.loadLibrary("mozglue");
- }
-
- public static void loadGeckoLibs(Context context, String apkName) {
- loadLibsSetup(context);
- loadGeckoLibsNative(apkName);
- }
-
- private static void setupLocaleEnvironment() {
- putenv("LANG=" + Locale.getDefault().toString());
- NumberFormat nf = NumberFormat.getInstance();
- if (nf instanceof DecimalFormat) {
- DecimalFormat df = (DecimalFormat)nf;
- DecimalFormatSymbols dfs = df.getDecimalFormatSymbols();
-
- putenv("LOCALE_DECIMAL_POINT=" + dfs.getDecimalSeparator());
- putenv("LOCALE_THOUSANDS_SEP=" + dfs.getGroupingSeparator());
- putenv("LOCALE_GROUPING=" + (char)df.getGroupingSize());
- }
- }
-
- // These methods are implemented in mozglue/android/nsGeckoUtils.cpp
- private static native void putenv(String map);
-
- // These methods are implemented in mozglue/android/APKOpen.cpp
- public static native void nativeRun(String args);
- private static native void loadGeckoLibsNative(String apkName);
- private static native void loadSQLiteLibsNative(String apkName, boolean shouldExtract);
- private static native void loadNSSLibsNative(String apkName, boolean shouldExtract);
-}
diff --git a/mobile/android/base/resources/layout/gecko_app.xml b/mobile/android/base/resources/layout/gecko_app.xml
deleted file mode 100644
index f9c35aac5..000000000
--- a/mobile/android/base/resources/layout/gecko_app.xml
+++ /dev/null
@@ -1,64 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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/. -->
-
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent">
-
- <org.mozilla.gecko.TabsPanel android:id="@+id/tabs_panel"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:background="@color/background_tabs"
- android:visibility="invisible"/>
-
- <view class="org.mozilla.gecko.GeckoApp$MainLayout"
- android:id="@+id/main_layout"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:background="@android:color/transparent">
-
- <RelativeLayout android:id="@+id/gecko_layout"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_above="@+id/find_in_page">
-
- <include layout="@layout/shared_ui_components"/>
-
- </RelativeLayout>
-
- <org.mozilla.gecko.FindInPageBar android:id="@+id/find_in_page"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- style="@style/FindBar"
- android:visibility="gone"/>
-
- <RelativeLayout android:id="@+id/camera_layout"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_alignParentBottom="true">
- </RelativeLayout>
-
- <include layout="@layout/browser_toolbar"
- android:layout_width="fill_parent"
- android:layout_height="@dimen/browser_toolbar_height"/>
- </view>
-
- <LinearLayout android:id="@+id/toast"
- style="@style/Toast">
-
- <TextView android:id="@+id/toast_message"
- style="@style/ToastMessage" />
-
- <ImageView android:id="@+id/toast_divider"
- style="@style/ToastDivider" />
-
- <Button android:id="@+id/toast_button"
- style="@style/ToastButton" />
-
- </LinearLayout>
-
-</RelativeLayout>
diff --git a/mobile/android/base/util/GeckoBackgroundThread.java b/mobile/android/base/util/GeckoBackgroundThread.java
deleted file mode 100644
index f7873fe73..000000000
--- a/mobile/android/base/util/GeckoBackgroundThread.java
+++ /dev/null
@@ -1,55 +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/. */
-
-package org.mozilla.gecko.util;
-
-import android.os.Handler;
-import android.os.Looper;
-
-import java.util.concurrent.SynchronousQueue;
-
-final class GeckoBackgroundThread extends Thread {
- private static final String LOOPER_NAME = "GeckoBackgroundThread";
-
- // Guarded by 'this'.
- private static Handler sHandler = null;
- private SynchronousQueue<Handler> mHandlerQueue = new SynchronousQueue<Handler>();
-
- // Singleton, so private constructor.
- private GeckoBackgroundThread() {
- super();
- }
-
- @Override
- public void run() {
- setName(LOOPER_NAME);
- Looper.prepare();
- try {
- mHandlerQueue.put(new Handler());
- } catch (InterruptedException ie) {}
-
- Looper.loop();
- }
-
- // Get a Handler for a looper thread, or create one if it doesn't yet exist.
- /*package*/ static synchronized Handler getHandler() {
- if (sHandler == null) {
- GeckoBackgroundThread lt = new GeckoBackgroundThread();
- ThreadUtils.setBackgroundThread(lt);
- lt.start();
- try {
- sHandler = lt.mHandlerQueue.take();
- } catch (InterruptedException ie) {}
- }
- return sHandler;
- }
-
- /*package*/ static void post(Runnable runnable) {
- Handler handler = getHandler();
- if (handler == null) {
- throw new IllegalStateException("No handler! Must have been interrupted. Not posting.");
- }
- handler.post(runnable);
- }
-}
diff --git a/mobile/android/base/util/GeckoEventListener.java b/mobile/android/base/util/GeckoEventListener.java
deleted file mode 100644
index ba37f0541..000000000
--- a/mobile/android/base/util/GeckoEventListener.java
+++ /dev/null
@@ -1,15 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; 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.gecko.util;
-
-import org.json.JSONObject;
-
-/* This class is referenced by Robocop via reflection; use care when
- * modifying the signature.
- */
-public interface GeckoEventListener {
- void handleMessage(String event, JSONObject message);
-}
diff --git a/mobile/android/base/util/GeckoEventResponder.java b/mobile/android/base/util/GeckoEventResponder.java
deleted file mode 100644
index dc4561561..000000000
--- a/mobile/android/base/util/GeckoEventResponder.java
+++ /dev/null
@@ -1,16 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * ***** BEGIN LICENSE BLOCK *****
- *
- * 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/.
- *
- * ***** END LICENSE BLOCK ***** */
-
-package org.mozilla.gecko.util;
-
-import org.json.JSONObject;
-
-public interface GeckoEventResponder extends GeckoEventListener {
- String getResponse(JSONObject response);
-}
diff --git a/mobile/android/base/util/GeckoJarReader.java b/mobile/android/base/util/GeckoJarReader.java
deleted file mode 100644
index 448af8bba..000000000
--- a/mobile/android/base/util/GeckoJarReader.java
+++ /dev/null
@@ -1,171 +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/. */
-
-package org.mozilla.gecko.util;
-
-import org.mozilla.gecko.mozglue.NativeZip;
-
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
-import android.util.Log;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.URL;
-import java.util.Stack;
-
-/* Reads out of a multiple level deep jar file such as
- * jar:jar:file:///data/app/org.mozilla.fennec.apk!/omni.ja!/chrome/chrome/content/branding/favicon32.png
- */
-public final class GeckoJarReader {
- private static final String LOGTAG = "GeckoJarReader";
-
- private GeckoJarReader() {}
-
- public static Bitmap getBitmap(Resources resources, String url) {
- BitmapDrawable drawable = getBitmapDrawable(resources, url);
- return (drawable != null) ? drawable.getBitmap() : null;
- }
-
- public static BitmapDrawable getBitmapDrawable(Resources resources, String url) {
- Stack<String> jarUrls = parseUrl(url);
- InputStream inputStream = null;
- BitmapDrawable bitmap = null;
-
- NativeZip zip = null;
- try {
- // Load the initial jar file as a zip
- zip = getZipFile(jarUrls.pop());
- inputStream = getStream(zip, jarUrls, url);
- if (inputStream != null) {
- bitmap = new BitmapDrawable(resources, inputStream);
- }
- } catch (IOException ex) {
- Log.e(LOGTAG, "Exception ", ex);
- } finally {
- if (inputStream != null) {
- try {
- inputStream.close();
- } catch(IOException ex) {
- Log.e(LOGTAG, "Error closing stream", ex);
- }
- }
- if (zip != null) {
- zip.close();
- }
- }
-
- return bitmap;
- }
-
- public static String getText(String url) {
- Stack<String> jarUrls = parseUrl(url);
-
- NativeZip zip = null;
- BufferedReader reader = null;
- String text = null;
- try {
- zip = getZipFile(jarUrls.pop());
- InputStream input = getStream(zip, jarUrls, url);
- if (input != null) {
- reader = new BufferedReader(new InputStreamReader(input));
- text = reader.readLine();
- }
- } catch (IOException ex) {
- Log.e(LOGTAG, "Exception ", ex);
- } finally {
- if (reader != null) {
- try {
- reader.close();
- } catch(IOException ex) {
- Log.e(LOGTAG, "Error closing reader", ex);
- }
- }
- if (zip != null) {
- zip.close();
- }
- }
-
- return text;
- }
-
- private static NativeZip getZipFile(String url) throws IOException {
- URL fileUrl = new URL(url);
- return new NativeZip(fileUrl.getPath());
- }
-
- // Public for testing only.
- public static InputStream getStream(String url) {
- Stack<String> jarUrls = parseUrl(url);
- try {
- NativeZip zip = getZipFile(jarUrls.pop());
- return getStream(zip, jarUrls, url);
- } catch (Exception ex) {
- // Some JNI code throws IllegalArgumentException on a bad file name;
- // swallow the error and return null. We could also see legitimate
- // IOExceptions here.
- return null;
- }
- }
-
- private static InputStream getStream(NativeZip zip, Stack<String> jarUrls, String origUrl) {
- InputStream inputStream = null;
-
- // loop through children jar files until we reach the innermost one
- while (!jarUrls.empty()) {
- String fileName = jarUrls.pop();
-
- if (inputStream != null) {
- // intermediate NativeZips and InputStreams will be garbage collected.
- try {
- zip = new NativeZip(inputStream);
- } catch (IllegalArgumentException e) {
- String description = "!!! BUG 849589 !!! origUrl=" + origUrl;
- Log.e(LOGTAG, description, e);
- throw new IllegalArgumentException(description);
- }
- }
-
- inputStream = zip.getInputStream(fileName);
- if (inputStream == null) {
- Log.d(LOGTAG, "No Entry for " + fileName);
- return null;
- }
- }
-
- return inputStream;
- }
-
- /* Returns a stack of strings breaking the url up into pieces. Each piece
- * is assumed to point to a jar file except for the final one. Callers should
- * pass in the url to parse, and null for the parent parameter (used for recursion)
- * For example, jar:jar:file:///data/app/org.mozilla.fennec.apk!/omni.ja!/chrome/chrome/content/branding/favicon32.png
- * will return:
- * file:///data/app/org.mozilla.fennec.apk
- * omni.ja
- * chrome/chrome/content/branding/favicon32.png
- */
- private static Stack<String> parseUrl(String url) {
- return parseUrl(url, null);
- }
-
- private static Stack<String> parseUrl(String url, Stack<String> results) {
- if (results == null) {
- results = new Stack<String>();
- }
-
- if (url.startsWith("jar:")) {
- int jarEnd = url.lastIndexOf("!");
- String subStr = url.substring(4, jarEnd);
- results.push(url.substring(jarEnd+2)); // remove the !/ characters
- return parseUrl(subStr, results);
- } else {
- results.push(url);
- return results;
- }
- }
-}
diff --git a/mobile/android/base/widget/GeckoActionProvider.java b/mobile/android/base/widget/GeckoActionProvider.java
deleted file mode 100644
index 750613d8b..000000000
--- a/mobile/android/base/widget/GeckoActionProvider.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; 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.gecko.widget;
-
-import org.mozilla.gecko.menu.MenuItemActionView;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.graphics.drawable.Drawable;
-import android.view.ActionProvider;
-import android.view.MenuItem;
-import android.view.MenuItem.OnMenuItemClickListener;
-import android.view.SubMenu;
-import android.view.View;
-import android.view.View.OnClickListener;
-
-public class GeckoActionProvider extends ActionProvider {
-
- /**
- * A listener to know when a target was selected.
- * When setting a provider, the activity can listen to this,
- * to close the menu.
- */
- public interface OnTargetSelectedListener {
- public void onTargetSelected();
- }
-
- private final Context mContext;
-
- public static final String DEFAULT_HISTORY_FILE_NAME = "history.xml";
-
- // History file.
- private String mHistoryFileName = DEFAULT_HISTORY_FILE_NAME;
-
- private OnTargetSelectedListener mOnTargetListener;
-
- private final Callbacks mCallbacks = new Callbacks();
-
- public GeckoActionProvider(Context context) {
- super(context);
- mContext = context;
- }
-
- @Override
- public View onCreateActionView() {
- // Create the view and set its data model.
- ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mHistoryFileName);
- MenuItemActionView view = new MenuItemActionView(mContext, null);
- view.setActionButtonClickListener(mCallbacks);
-
- if (dataModel.getHistorySize() > 0) {
- PackageManager packageManager = mContext.getPackageManager();
- ResolveInfo defaultActivity = dataModel.getDefaultActivity();
- view.setActionButton(defaultActivity == null ? null : defaultActivity.loadIcon(packageManager));
- }
-
- return view;
- }
-
- public View getView() {
- return onCreateActionView();
- }
-
- @Override
- public boolean hasSubMenu() {
- return true;
- }
-
- @Override
- public void onPrepareSubMenu(SubMenu subMenu) {
- // Clear since the order of items may change.
- subMenu.clear();
-
- ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mHistoryFileName);
- PackageManager packageManager = mContext.getPackageManager();
-
- // Populate the sub-menu with a sub set of the activities.
- final int count = dataModel.getActivityCount();
- for (int i = 0; i < count; i++) {
- ResolveInfo activity = dataModel.getActivity(i);
- subMenu.add(0, i, i, activity.loadLabel(packageManager))
- .setIcon(activity.loadIcon(packageManager))
- .setOnMenuItemClickListener(mCallbacks);
- }
- }
-
- public void setHistoryFileName(String historyFile) {
- mHistoryFileName = historyFile;
- }
-
- public Intent getIntent() {
- ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mHistoryFileName);
- return dataModel.getIntent();
- }
-
- public void setIntent(Intent intent) {
- ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mHistoryFileName);
- dataModel.setIntent(intent);
- }
-
- public void setOnTargetSelectedListener(OnTargetSelectedListener listener) {
- mOnTargetListener = listener;
- }
-
- /**
- * Listener for handling default activity / menu item clicks.
- */
- private class Callbacks implements OnMenuItemClickListener,
- OnClickListener {
- private void chooseActivity(int index) {
- if (mOnTargetListener != null)
- mOnTargetListener.onTargetSelected();
-
- ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mHistoryFileName);
- Intent launchIntent = dataModel.chooseActivity(index);
- if (launchIntent != null) {
- launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
- mContext.startActivity(launchIntent);
- }
- }
-
- @Override
- public boolean onMenuItemClick(MenuItem item) {
- chooseActivity(item.getItemId());
- return true;
- }
-
- @Override
- public void onClick(View view) {
- ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mHistoryFileName);
- chooseActivity(dataModel.getActivityIndex(dataModel.getDefaultActivity()));
- }
- }
-}
-
diff --git a/mobile/android/base/widget/GeckoPopupMenu.java b/mobile/android/base/widget/GeckoPopupMenu.java
deleted file mode 100644
index 9814ec455..000000000
--- a/mobile/android/base/widget/GeckoPopupMenu.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; 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.gecko.widget;
-
-import org.mozilla.gecko.menu.GeckoMenu;
-import org.mozilla.gecko.menu.GeckoMenuInflater;
-import org.mozilla.gecko.menu.MenuPanel;
-import org.mozilla.gecko.menu.MenuPopup;
-
-import android.content.Context;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-
-/**
- * A PopupMenu that uses the custom GeckoMenu. This menu is
- * usually tied to an anchor, and show as a dropdrown from the anchor.
- */
-public class GeckoPopupMenu implements GeckoMenu.Callback,
- GeckoMenu.MenuPresenter {
-
- // An interface for listeners for dismissal.
- public static interface OnDismissListener {
- public boolean onDismiss(GeckoMenu menu);
- }
-
- // An interface for listeners for menu item click events.
- public static interface OnMenuItemClickListener {
- public boolean onMenuItemClick(MenuItem item);
- }
-
- private View mAnchor;
-
- private MenuPopup mMenuPopup;
- private MenuPanel mMenuPanel;
-
- private GeckoMenu mMenu;
- private GeckoMenuInflater mMenuInflater;
-
- private OnDismissListener mDismissListener;
- private OnMenuItemClickListener mClickListener;
-
- public GeckoPopupMenu(Context context) {
- initialize(context, null);
- }
-
- public GeckoPopupMenu(Context context, View anchor) {
- initialize(context, anchor);
- }
-
- /**
- * This method creates an empty menu and attaches the necessary listeners.
- * If an anchor is supplied, it is stored as well.
- */
- private void initialize(Context context, View anchor) {
- mMenu = new GeckoMenu(context, null);
- mMenu.setCallback(this);
- mMenu.setMenuPresenter(this);
- mMenuInflater = new GeckoMenuInflater(context);
-
- mMenuPopup = new MenuPopup(context);
- mMenuPanel = new MenuPanel(context, null);
-
- setAnchor(anchor);
- }
-
- /**
- * Returns the menu that is current being shown.
- *
- * @return The menu being shown.
- */
- public Menu getMenu() {
- return mMenu;
- }
-
- /**
- * Returns the menu inflater that was used to create the menu.
- *
- * @return The menu inflater used.
- */
- public MenuInflater getMenuInflater() {
- return mMenuInflater;
- }
-
- /**
- * Inflates a menu resource to the menu using the menu inflater.
- *
- * @param menuRes The menu resource to be inflated.
- */
- public void inflate(int menuRes) {
- mMenuInflater.inflate(menuRes, mMenu);
-
- mMenuPanel.addView(mMenu);
- mMenuPopup.setPanelView(mMenuPanel);
- }
-
- /**
- * Set a different anchor after the menu is inflated.
- *
- * @param anchor The new anchor for the popup.
- */
- public void setAnchor(View anchor) {
- mAnchor = anchor;
- }
-
- public void setOnDismissListener(OnDismissListener listener) {
- mDismissListener = listener;
- }
-
- public void setOnMenuItemClickListener(OnMenuItemClickListener listener) {
- mClickListener = listener;
- }
-
- /**
- * Show the inflated menu.
- */
- public void show() {
- if (!mMenuPopup.isShowing())
- mMenuPopup.showAsDropDown(mAnchor);
- }
-
- /**
- * Hide the inflated menu.
- */
- public void dismiss() {
- if (mMenuPopup.isShowing()) {
- mMenuPopup.dismiss();
-
- if (mDismissListener != null)
- mDismissListener.onDismiss(mMenu);
- }
- }
-
- /**
- * Show/hide the arrow pointing to the anchor.
- *
- * @param show Show/hide the arrow.
- */
- public void showArrowToAnchor(boolean show) {
- mMenuPopup.showArrowToAnchor(show);
- }
-
- @Override
- public boolean onMenuItemSelected(MenuItem item) {
- if (mClickListener != null)
- return mClickListener.onMenuItemClick(item);
-
- return false;
- }
-
- @Override
- public void openMenu() {
- show();
- }
-
- @Override
- public void showMenu(View menu) {
- mMenuPanel.removeAllViews();
- mMenuPanel.addView(menu);
-
- openMenu();
- }
-
- @Override
- public void closeMenu() {
- dismiss();
- }
-}
diff --git a/mozglue/android/nsGeckoUtils.cpp b/mozglue/android/nsGeckoUtils.cpp
deleted file mode 100644
index 0a5e327a7..000000000
--- a/mozglue/android/nsGeckoUtils.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; 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/. */
-
-#include <jni.h>
-
-#include <stdlib.h>
-#include <fcntl.h>
-#include "APKOpen.h"
-#include "Zip.h"
-#include "mozilla/RefPtr.h"
-
-extern "C"
-__attribute__ ((visibility("default")))
-void JNICALL
-Java_org_mozilla_gecko_mozglue_GeckoLoader_putenv(JNIEnv *jenv, jclass, jstring map)
-{
- const char* str;
- // XXX: java doesn't give us true UTF8, we should figure out something
- // better to do here
- str = jenv->GetStringUTFChars(map, NULL);
- if (str == NULL)
- return;
- putenv(strdup(str));
- jenv->ReleaseStringUTFChars(map, str);
-}
-
-extern "C"
-__attribute__ ((visibility("default")))
-jobject JNICALL
-Java_org_mozilla_gecko_mozglue_DirectBufferAllocator_nativeAllocateDirectBuffer(JNIEnv *jenv, jclass, jlong size)
-{
- jobject buffer = NULL;
- void* mem = malloc(size);
- if (mem) {
- buffer = jenv->NewDirectByteBuffer(mem, size);
- if (!buffer)
- free(mem);
- }
- return buffer;
-}
-
-extern "C"
-__attribute__ ((visibility("default")))
-void JNICALL
-Java_org_mozilla_gecko_mozglue_DirectBufferAllocator_nativeFreeDirectBuffer(JNIEnv *jenv, jclass, jobject buf)
-{
- free(jenv->GetDirectBufferAddress(buf));
-}
-
-extern "C"
-__attribute__ ((visibility("default")))
-jlong JNICALL
-Java_org_mozilla_gecko_mozglue_NativeZip_getZip(JNIEnv *jenv, jclass, jstring path)
-{
- const char* str;
- str = jenv->GetStringUTFChars(path, NULL);
- if (!str || !*str) {
- if (str)
- jenv->ReleaseStringUTFChars(path, str);
- JNI_Throw(jenv, "java/lang/IllegalArgumentException", "Invalid path");
- return 0;
- }
- mozilla::RefPtr<Zip> zip = ZipCollection::GetZip(str);
- jenv->ReleaseStringUTFChars(path, str);
- if (!zip) {
- JNI_Throw(jenv, "java/lang/IllegalArgumentException", "Invalid path or invalid zip");
- return 0;
- }
- zip->AddRef();
- return (jlong) zip.get();
-}
-
-extern "C"
-__attribute__ ((visibility("default")))
-jlong JNICALL
-Java_org_mozilla_gecko_mozglue_NativeZip_getZipFromByteBuffer(JNIEnv *jenv, jclass, jobject buffer)
-{
- void *buf = jenv->GetDirectBufferAddress(buffer);
- size_t size = jenv->GetDirectBufferCapacity(buffer);
- mozilla::RefPtr<Zip> zip = Zip::Create(buf, size);
- if (!zip) {
- JNI_Throw(jenv, "java/lang/IllegalArgumentException", "Invalid zip");
- return 0;
- }
- zip->AddRef();
- return (jlong) zip.get();
-}
-
- extern "C"
-__attribute__ ((visibility("default")))
-void JNICALL
-Java_org_mozilla_gecko_mozglue_NativeZip__1release(JNIEnv *jenv, jclass, jlong obj)
-{
- Zip *zip = (Zip *)obj;
- zip->Release();
-}
-
-extern "C"
-__attribute__ ((visibility("default")))
-jobject JNICALL
-Java_org_mozilla_gecko_mozglue_NativeZip__1getInputStream(JNIEnv *jenv, jobject jzip, jlong obj, jstring path)
-{
- Zip *zip = (Zip *)obj;
- const char* str;
- str = jenv->GetStringUTFChars(path, NULL);
-
- Zip::Stream stream;
- bool res = zip->GetStream(str, &stream);
- jenv->ReleaseStringUTFChars(path, str);
- if (!res) {
- return NULL;
- }
- jobject buf = jenv->NewDirectByteBuffer(const_cast<void *>(stream.GetBuffer()), stream.GetSize());
- if (!buf) {
- JNI_Throw(jenv, "java/lang/RuntimeException", "Failed to create ByteBuffer");
- return NULL;
- }
- jclass nativeZip = jenv->GetObjectClass(jzip);
- jmethodID method = jenv->GetMethodID(nativeZip, "createInputStream", "(Ljava/nio/ByteBuffer;I)Ljava/io/InputStream;");
- // Since this function is only expected to be called from Java, it is safe
- // to skip exception checking for the method call below, as long as no
- // other Native -> Java call doesn't happen before returning to Java.
- return jenv->CallObjectMethod(jzip, method, buf, (jint) stream.GetType());
-}
diff --git a/tools/profiler/GeckoProfiler.h b/tools/profiler/GeckoProfiler.h
deleted file mode 100644
index d5d28ad2c..000000000
--- a/tools/profiler/GeckoProfiler.h
+++ /dev/null
@@ -1,166 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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/. */
-
-/* *************** SPS Sampler Information ****************
- *
- * SPS is an always on profiler that takes fast and low overheads samples
- * of the program execution using only userspace functionity for portability.
- * The goal of this module is to provide performance data in a generic
- * cross platform way without requiring custom tools or kernel support.
- *
- * Non goals: Support features that are platform specific or replace
- * platform specific profilers.
- *
- * Samples are collected to form a timeline with optional timeline event (markers)
- * used for filtering.
- *
- * SPS collects samples in a platform independant way by using a speudo stack abstraction
- * of the real program stack by using 'sample stack frames'. When a sample is collected
- * all active sample stack frames and the program counter are recorded.
- */
-
-/* *************** SPS Sampler File Format ****************
- *
- * Simple new line seperated tag format:
- * S -> BOF tags EOF
- * tags -> tag tags
- * tag -> CHAR - STRING
- *
- * Tags:
- * 's' - Sample tag followed by the first stack frame followed by 0 or more 'c' tags.
- * 'c' - Continue Sample tag gives remaining tag element. If a 'c' tag is seen without
- * a preceding 's' tag it should be ignored. This is to support the behavior
- * of circular buffers.
- * If the 'stackwalk' feature is enabled this tag will have the format
- * 'l-<library name>@<hex address>' and will expect an external tool to translate
- * the tag into something readable through a symbolication processing step.
- * 'm' - Timeline marker. Zero or more may appear before a 's' tag.
- * 'l' - Information about the program counter library and address. Post processing
- * can include function and source line. If built with leaf data enabled
- * this tag will describe the last 'c' tag.
- * 'r' - Responsiveness tag following an 's' tag. Gives an indication on how well the
- * application is responding to the event loop. Lower is better.
- * 't' - Elapse time since recording started.
- *
- */
-
-#ifndef SAMPLER_H
-#define SAMPLER_H
-
-#include "jsfriendapi.h"
-#include "mozilla/NullPtr.h"
-#include "mozilla/TimeStamp.h"
-
-#ifndef MOZ_ENABLE_PROFILER_SPS
-
-// Insert a RAII in this scope to active a pseudo label. Any samples collected
-// in this scope will contain this annotation. For dynamic strings use
-// PROFILER_LABEL_PRINTF. Arguments must be string literals.
-#define PROFILER_LABEL(name_space, info) do {} while (0)
-
-// Format a dynamic string as a pseudo label. These labels will a considerable
-// storage size in the circular buffer compared to regular labels. This function
-// can be used to annotate custom information such as URL for the resource being
-// decoded or the size of the paint.
-#define PROFILER_LABEL_PRINTF(name_space, info, format, ...) do {} while (0)
-
-// Insert a marker in the profile timeline. This is useful to delimit something
-// important happening such as the first paint. Unlike profiler_label that are
-// only recorded if a sample is collected while it is active, marker will always
-// be collected.
-#define PROFILER_MARKER(info) do {} while (0)
-
-// Main thread specilization to avoid TLS lookup for performance critical use.
-#define PROFILER_MAIN_THREAD_LABEL(name_space, info) do {} while (0)
-#define PROFILER_MAIN_THREAD_LABEL_PRINTF(name_space, info, format, ...) do {} while (0)
-
-// Initilize the profiler TLS, signal handlers on linux. If MOZ_PROFILER_STARTUP
-// is set the profiler will be started. This call must happen before any other
-// sampler calls. Particularly sampler_label/sampler_marker.
-static inline void profiler_init(void* stackTop) {};
-
-// Clean up the profiler module, stopping it if required. This function may
-// also save a shutdown profile if requested. No profiler calls should happen
-// after this point and all pseudo labels should have been popped.
-static inline void profiler_shutdown() {};
-
-// Start the profiler with the selected options. The samples will be
-// recorded in a circular buffer.
-// "aProfileEntries" is an abstract size indication of how big
-// the profile's circular buffer should be. Multiply by 4
-// words to get the cost.
-// "aInterval" the sampling interval. The profiler will do its
-// best to sample at this interval. The profiler visualization
-// should represent the actual sampling accuracy.
-static inline void profiler_start(int aProfileEntries, int aInterval,
- const char** aFeatures, uint32_t aFeatureCount,
- const char** aThreadNameFilters, uint32_t aFilterCount) {}
-
-// Stop the profiler and discard the profile. Call 'profiler_save' before this
-// to retrieve the profile.
-static inline void profiler_stop() {}
-
-static inline bool profiler_is_active() { return false; }
-
-// Internal-only. Used by the event tracer.
-static inline void profiler_responsiveness(const mozilla::TimeStamp& aTime) {}
-
-// Internal-only. Used by the event tracer.
-static inline double* profiler_get_responsiveness() { return nullptr; }
-
-// Internal-only.
-static inline void profiler_set_frame_number(int frameNumber) {}
-
-// Get the profile encoded as a JSON string.
-static inline char* profiler_get_profile() { return nullptr; }
-
-// Get the profile encoded as a JSON object.
-static inline JSObject* profiler_get_profile_jsobject(JSContext* aCx) { return nullptr; }
-
-// Get the features supported by the profiler that are accepted by profiler_init.
-// Returns a null terminated char* array.
-static inline char** profiler_get_features() { return nullptr; }
-
-// Print the current location to the console. This functill will do it best effort
-// to show the profiler's combined js/c++ if the profiler is running. Note that
-// printing the location require symbolicating which is very slow.
-static inline void profiler_print_location() {}
-
-// Discard the profile, throw away the profile and notify 'profiler-locked'.
-// This function is to be used when entering private browsing to prevent
-// the profiler from collecting sensitive data.
-static inline void profiler_lock() {}
-
-// Re-enable the profiler and notify 'profiler-unlocked'.
-static inline void profiler_unlock() {}
-
-static inline void profiler_register_thread(const char* name, void* stackTop) {}
-static inline void profiler_unregister_thread() {}
-
-// Call by the JSRuntime's operation callback. This is used to enable
-// profiling on auxilerary threads.
-static inline void profiler_js_operation_callback() {}
-
-static inline double profiler_time() { return 0; }
-
-static inline bool profiler_in_privacy_mode() { return false; }
-
-#else
-
-#include "GeckoProfilerImpl.h"
-
-#endif
-
-class GeckoProfilerInitRAII {
-public:
- GeckoProfilerInitRAII(void* stackTop) {
- profiler_init(stackTop);
- }
- ~GeckoProfilerInitRAII() {
- profiler_shutdown();
- }
-};
-
-#endif // ifndef SAMPLER_H
diff --git a/tools/profiler/GeckoProfilerFunc.h b/tools/profiler/GeckoProfilerFunc.h
deleted file mode 100644
index 831520f1d..000000000
--- a/tools/profiler/GeckoProfilerFunc.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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/. */
-
-#ifndef PROFILER_FUNCS_H
-#define PROFILER_FUNCS_H
-
-#include "mozilla/NullPtr.h"
-#include "mozilla/StandardInteger.h"
-#include "mozilla/TimeStamp.h"
-#include "jsfriendapi.h"
-
-using mozilla::TimeStamp;
-using mozilla::TimeDuration;
-
-// Returns a handle to pass on exit. This can check that we are popping the
-// correct callstack.
-inline void* mozilla_sampler_call_enter(const char *aInfo, void *aFrameAddress = NULL,
- bool aCopy = false, uint32_t line = 0);
-inline void mozilla_sampler_call_exit(void* handle);
-inline void mozilla_sampler_add_marker(const char *aInfo);
-
-void mozilla_sampler_start(int aEntries, int aInterval,
- const char** aFeatures, uint32_t aFeatureCount,
- const char** aThreadNameFilters, uint32_t aFilterCount);
-
-void mozilla_sampler_stop();
-
-bool mozilla_sampler_is_active();
-
-void mozilla_sampler_responsiveness(const TimeStamp& time);
-
-void mozilla_sampler_frame_number(int frameNumber);
-
-const double* mozilla_sampler_get_responsiveness();
-
-void mozilla_sampler_save();
-
-char* mozilla_sampler_get_profile();
-
-JSObject *mozilla_sampler_get_profile_data(JSContext *aCx);
-
-const char** mozilla_sampler_get_features();
-
-void mozilla_sampler_init(void* stackTop);
-
-void mozilla_sampler_shutdown();
-
-void mozilla_sampler_print_location1();
-void mozilla_sampler_print_location2();
-
-// Lock the profiler. When locked the profiler is (1) stopped,
-// (2) profile data is cleared, (3) profiler-locked is fired.
-// This is used to lock down the profiler during private browsing
-void mozilla_sampler_lock();
-
-// Unlock the profiler, leaving it stopped and fires profiler-unlocked.
-void mozilla_sampler_unlock();
-
-// Register/unregister threads with the profiler
-bool mozilla_sampler_register_thread(const char* name, void* stackTop);
-void mozilla_sampler_unregister_thread();
-
-double mozilla_sampler_time();
-
-/* Returns true if env var SPS_NEW is set to anything, else false. */
-extern bool sps_version2();
-
-#endif
-
diff --git a/tools/profiler/GeckoProfilerImpl.h b/tools/profiler/GeckoProfilerImpl.h
deleted file mode 100644
index 02e53ba8b..000000000
--- a/tools/profiler/GeckoProfilerImpl.h
+++ /dev/null
@@ -1,350 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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/. */
-
-#ifndef TOOLS_SPS_SAMPLER_H_
-#define TOOLS_SPS_SAMPLER_H_
-
-#include <stdlib.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <algorithm>
-#include "mozilla/ThreadLocal.h"
-#include "mozilla/Assertions.h"
-#include "mozilla/TimeStamp.h"
-#include "mozilla/Util.h"
-#include "nsAlgorithm.h"
-#include "nscore.h"
-#include "jsfriendapi.h"
-#include "GeckoProfilerFunc.h"
-#include "PseudoStack.h"
-#include "nsISupports.h"
-
-/* QT has a #define for the word "slots" and jsfriendapi.h has a struct with
- * this variable name, causing compilation problems. Alleviate this for now by
- * removing this #define */
-#ifdef MOZ_WIDGET_QT
-#undef slots
-#endif
-
-// Make sure that we can use std::min here without the Windows headers messing with us.
-#ifdef min
-#undef min
-#endif
-
-struct PseudoStack;
-class TableTicker;
-class JSCustomObject;
-
-extern mozilla::ThreadLocal<PseudoStack *> tlsPseudoStack;
-extern mozilla::ThreadLocal<TableTicker *> tlsTicker;
-extern bool stack_key_initialized;
-
-#ifndef SAMPLE_FUNCTION_NAME
-# ifdef __GNUC__
-# define SAMPLE_FUNCTION_NAME __FUNCTION__
-# elif defined(_MSC_VER)
-# define SAMPLE_FUNCTION_NAME __FUNCTION__
-# else
-# define SAMPLE_FUNCTION_NAME __func__ // defined in C99, supported in various C++ compilers. Just raw function name.
-# endif
-#endif
-
-static inline
-void profiler_init(void* stackTop)
-{
- mozilla_sampler_init(stackTop);
-}
-
-static inline
-void profiler_shutdown()
-{
- mozilla_sampler_shutdown();
-}
-
-static inline
-void profiler_start(int aProfileEntries, int aInterval,
- const char** aFeatures, uint32_t aFeatureCount,
- const char** aThreadNameFilters, uint32_t aFilterCount)
-{
- mozilla_sampler_start(aProfileEntries, aInterval, aFeatures, aFeatureCount, aThreadNameFilters, aFilterCount);
-}
-
-static inline
-void profiler_stop()
-{
- mozilla_sampler_stop();
-}
-
-static inline
-bool profiler_is_active()
-{
- return mozilla_sampler_is_active();
-}
-
-static inline
-void profiler_responsiveness(const TimeStamp& aTime)
-{
- mozilla_sampler_responsiveness(aTime);
-}
-
-static inline
-const double* profiler_get_responsiveness()
-{
- return mozilla_sampler_get_responsiveness();
-}
-
-static inline
-void profiler_set_frame_number(int frameNumber)
-{
- return mozilla_sampler_frame_number(frameNumber);
-}
-
-static inline
-char* profiler_get_profile()
-{
- return mozilla_sampler_get_profile();
-}
-
-static inline
-JSObject* profiler_get_profile_jsobject(JSContext* aCx)
-{
- return mozilla_sampler_get_profile_data(aCx);
-}
-
-static inline
-const char** profiler_get_features()
-{
- return mozilla_sampler_get_features();
-}
-
-static inline
-void profiler_print_location()
-{
- if (!sps_version2()) {
- return mozilla_sampler_print_location1();
- } else {
- return mozilla_sampler_print_location2();
- }
-}
-
-static inline
-void profiler_lock()
-{
- return mozilla_sampler_lock();
-}
-
-static inline
-void profiler_unlock()
-{
- return mozilla_sampler_unlock();
-}
-
-static inline
-void profiler_register_thread(const char* name, void* stackTop)
-{
- mozilla_sampler_register_thread(name, stackTop);
-}
-
-static inline
-void profiler_unregister_thread()
-{
- mozilla_sampler_unregister_thread();
-}
-
-static inline
-void profiler_js_operation_callback()
-{
- PseudoStack *stack = tlsPseudoStack.get();
- if (!stack) {
- return;
- }
-
- stack->jsOperationCallback();
-}
-
-static inline
-double profiler_time()
-{
- return mozilla_sampler_time();
-}
-
-static inline
-bool profiler_in_privacy_mode()
-{
- PseudoStack *stack = tlsPseudoStack.get();
- if (!stack) {
- return false;
- }
- return stack->mPrivacyMode;
-}
-
-// we want the class and function name but can't easily get that using preprocessor macros
-// __func__ doesn't have the class name and __PRETTY_FUNCTION__ has the parameters
-
-#define SAMPLER_APPEND_LINE_NUMBER_PASTE(id, line) id ## line
-#define SAMPLER_APPEND_LINE_NUMBER_EXPAND(id, line) SAMPLER_APPEND_LINE_NUMBER_PASTE(id, line)
-#define SAMPLER_APPEND_LINE_NUMBER(id) SAMPLER_APPEND_LINE_NUMBER_EXPAND(id, __LINE__)
-
-#define PROFILER_LABEL(name_space, info) mozilla::SamplerStackFrameRAII SAMPLER_APPEND_LINE_NUMBER(sampler_raii)(name_space "::" info, __LINE__)
-#define PROFILER_LABEL_PRINTF(name_space, info, ...) mozilla::SamplerStackFramePrintfRAII SAMPLER_APPEND_LINE_NUMBER(sampler_raii)(name_space "::" info, __LINE__, __VA_ARGS__)
-#define PROFILER_MARKER(info) mozilla_sampler_add_marker(info)
-#define PROFILER_MAIN_THREAD_LABEL(name_space, info) MOZ_ASSERT(NS_IsMainThread(), "This can only be called on the main thread"); mozilla::SamplerStackFrameRAII SAMPLER_APPEND_LINE_NUMBER(sampler_raii)(name_space "::" info, __LINE__)
-#define PROFILER_MAIN_THREAD_LABEL_PRINTF(name_space, info, ...) MOZ_ASSERT(NS_IsMainThread(), "This can only be called on the main thread"); mozilla::SamplerStackFramePrintfRAII SAMPLER_APPEND_LINE_NUMBER(sampler_raii)(name_space "::" info, __LINE__, __VA_ARGS__)
-#define PROFILER_MAIN_THREAD_MARKER(info) MOZ_ASSERT(NS_IsMainThread(), "This can only be called on the main thread"); mozilla_sampler_add_marker(info)
-
-
-/* FIXME/bug 789667: memory constraints wouldn't much of a problem for
- * this small a sample buffer size, except that serializing the
- * profile data is extremely, unnecessarily memory intensive. */
-#ifdef MOZ_WIDGET_GONK
-# define PLATFORM_LIKELY_MEMORY_CONSTRAINED
-#endif
-
-#if !defined(PLATFORM_LIKELY_MEMORY_CONSTRAINED) && !defined(ARCH_ARMV6)
-# define PROFILE_DEFAULT_ENTRY 1000000
-#else
-# define PROFILE_DEFAULT_ENTRY 100000
-#endif
-
-#if defined(PLATFORM_LIKELY_MEMORY_CONSTRAINED)
-/* A 1ms sampling interval has been shown to be a large perf hit
- * (10fps) on memory-contrained (low-end) platforms, and additionally
- * to yield different results from the profiler. Where this is the
- * important case, b2g, there are also many gecko processes which
- * magnify these effects. */
-# define PROFILE_DEFAULT_INTERVAL 10
-#elif defined(ANDROID)
-// We use a lower frequency on Android, in order to make things work
-// more smoothly on phones. This value can be adjusted later with
-// some libunwind optimizations.
-// In one sample measurement on Galaxy Nexus, out of about 700 backtraces,
-// 60 of them took more than 25ms, and the average and standard deviation
-// were 6.17ms and 9.71ms respectively.
-
-// For now since we don't support stackwalking let's use 1ms since it's fast
-// enough.
-#define PROFILE_DEFAULT_INTERVAL 1
-#else
-#define PROFILE_DEFAULT_INTERVAL 1
-#endif
-#define PROFILE_DEFAULT_FEATURES NULL
-#define PROFILE_DEFAULT_FEATURE_COUNT 0
-
-namespace mozilla {
-
-class MOZ_STACK_CLASS SamplerStackFrameRAII {
-public:
- // we only copy the strings at save time, so to take multiple parameters we'd need to copy them then.
- SamplerStackFrameRAII(const char *aInfo, uint32_t line) {
- mHandle = mozilla_sampler_call_enter(aInfo, this, false, line);
- }
- ~SamplerStackFrameRAII() {
- mozilla_sampler_call_exit(mHandle);
- }
-private:
- void* mHandle;
-};
-
-static const int SAMPLER_MAX_STRING = 128;
-class MOZ_STACK_CLASS SamplerStackFramePrintfRAII {
-public:
- // we only copy the strings at save time, so to take multiple parameters we'd need to copy them then.
- SamplerStackFramePrintfRAII(const char *aDefault, uint32_t line, const char *aFormat, ...) {
- if (profiler_is_active() && !profiler_in_privacy_mode()) {
- va_list args;
- va_start(args, aFormat);
- char buff[SAMPLER_MAX_STRING];
-
- // We have to use seperate printf's because we're using
- // the vargs.
-#if _MSC_VER
- _vsnprintf(buff, SAMPLER_MAX_STRING, aFormat, args);
- _snprintf(mDest, SAMPLER_MAX_STRING, "%s %s", aDefault, buff);
-#else
- vsnprintf(buff, SAMPLER_MAX_STRING, aFormat, args);
- snprintf(mDest, SAMPLER_MAX_STRING, "%s %s", aDefault, buff);
-#endif
- mHandle = mozilla_sampler_call_enter(mDest, this, true, line);
- va_end(args);
- } else {
- mHandle = mozilla_sampler_call_enter(aDefault, NULL, false, line);
- }
- }
- ~SamplerStackFramePrintfRAII() {
- mozilla_sampler_call_exit(mHandle);
- }
-private:
- char mDest[SAMPLER_MAX_STRING];
- void* mHandle;
-};
-
-} //mozilla
-
-inline PseudoStack* mozilla_get_pseudo_stack(void)
-{
- if (!stack_key_initialized)
- return NULL;
- return tlsPseudoStack.get();
-}
-
-inline void* mozilla_sampler_call_enter(const char *aInfo, void *aFrameAddress,
- bool aCopy, uint32_t line)
-{
- // check if we've been initialized to avoid calling pthread_getspecific
- // with a null tlsStack which will return undefined results.
- if (!stack_key_initialized)
- return NULL;
-
- PseudoStack *stack = tlsPseudoStack.get();
- // we can't infer whether 'stack' has been initialized
- // based on the value of stack_key_intiailized because
- // 'stack' is only intialized when a thread is being
- // profiled.
- if (!stack) {
- return stack;
- }
- stack->push(aInfo, aFrameAddress, aCopy, line);
-
- // The handle is meant to support future changes
- // but for now it is simply use to save a call to
- // pthread_getspecific on exit. It also supports the
- // case where the sampler is initialized between
- // enter and exit.
- return stack;
-}
-
-inline void mozilla_sampler_call_exit(void *aHandle)
-{
- if (!aHandle)
- return;
-
- PseudoStack *stack = (PseudoStack*)aHandle;
- stack->pop();
-}
-
-inline void mozilla_sampler_add_marker(const char *aMarker)
-{
- if (!stack_key_initialized)
- return;
-
- // Don't insert a marker if we're not profiling to avoid
- // the heap copy (malloc).
- if (!profiler_is_active()) {
- return;
- }
-
- // Don't add a marker if we don't want to include personal information
- if (profiler_in_privacy_mode()) {
- return;
- }
-
- PseudoStack *stack = tlsPseudoStack.get();
- if (!stack) {
- return;
- }
- stack->addMarker(aMarker);
-}
-
-#endif /* ndef TOOLS_SPS_SAMPLER_H_ */