mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 847839 - Part 2: Remove obsolete files for Android XUL Fennec. r=mfinkle
This commit is contained in:
parent
41b11690cb
commit
e52b304c31
@ -10,7 +10,6 @@ namespace dom {
|
||||
|
||||
// Make sure that any change here is also made in
|
||||
// * mobile/android/base/GeckoScreenOrientationListener.java
|
||||
// * embedding/android/GeckoScreenOrientationListener.java
|
||||
typedef uint32_t ScreenOrientation;
|
||||
|
||||
static const ScreenOrientation eScreenOrientation_None = 0;
|
||||
|
@ -18,7 +18,7 @@ interface nsIMobileMessageCallback : nsISupports
|
||||
/**
|
||||
* All SMS related errors that could apply to SmsRequest objects.
|
||||
* Make sure to keep this list in sync with the list in:
|
||||
* embedding/android/GeckoSmsManager.java
|
||||
* mobile/android/GeckoSmsManager.java
|
||||
*/
|
||||
const unsigned short SUCCESS_NO_ERROR = 0;
|
||||
const unsigned short NO_SIGNAL_ERROR = 1;
|
||||
|
@ -14,7 +14,7 @@ namespace mobilemessage {
|
||||
|
||||
// For MmsMessageData.state and SmsMessageData.deliveryState
|
||||
// Please keep the following files in sync with enum below:
|
||||
// embedding/android/GeckoSmsManager.java
|
||||
// mobile/android/base/GeckoSmsManager.java
|
||||
enum DeliveryState {
|
||||
eDeliveryState_Sent = 0,
|
||||
eDeliveryState_Received,
|
||||
|
@ -1,113 +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.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.graphics.*;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
import android.widget.RemoteViews;
|
||||
import java.net.*;
|
||||
import java.text.NumberFormat;
|
||||
|
||||
public class AlertNotification
|
||||
extends Notification
|
||||
{
|
||||
Context mContext;
|
||||
int mId;
|
||||
int mIcon;
|
||||
String mTitle;
|
||||
String mText;
|
||||
boolean mProgressStyle;
|
||||
NotificationManager mNotificationManager;
|
||||
double mPrevPercent = -1;
|
||||
String mPrevAlertText = "";
|
||||
static final double UPDATE_THRESHOLD = .01;
|
||||
|
||||
public AlertNotification(Context aContext, int aNotificationId, int aIcon,
|
||||
String aTitle, String aText, long aWhen) {
|
||||
super(aIcon, (aText.length() > 0) ? aText : aTitle, aWhen);
|
||||
|
||||
mContext = aContext;
|
||||
mIcon = aIcon;
|
||||
mTitle = aTitle;
|
||||
mText = aText;
|
||||
mProgressStyle = false;
|
||||
mId = aNotificationId;
|
||||
|
||||
mNotificationManager = (NotificationManager)
|
||||
mContext.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
}
|
||||
|
||||
public boolean isProgressStyle() {
|
||||
return mProgressStyle;
|
||||
}
|
||||
|
||||
public void show() {
|
||||
mNotificationManager.notify(mId, this);
|
||||
}
|
||||
|
||||
public void setCustomIcon(Uri aIconUri) {
|
||||
if (aIconUri == null || aIconUri.getScheme() == null)
|
||||
return;
|
||||
|
||||
// Custom view
|
||||
int layout = R.layout.notification_icon_text;
|
||||
RemoteViews view = new RemoteViews(GeckoApp.mAppContext.getPackageName(), layout);
|
||||
try {
|
||||
URL url = new URL(aIconUri.toString());
|
||||
Bitmap bm = BitmapFactory.decodeStream(url.openStream());
|
||||
view.setImageViewBitmap(R.id.notificationImage, bm);
|
||||
view.setTextViewText(R.id.notificationTitle, mTitle);
|
||||
if (mText.length() > 0) {
|
||||
view.setTextViewText(R.id.notificationText, mText);
|
||||
}
|
||||
contentView = view;
|
||||
mNotificationManager.notify(mId, this);
|
||||
} catch(Exception ex) {
|
||||
Log.e("GeckoAlert", "failed to create bitmap", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateProgress(String aAlertText, long aProgress, long aProgressMax) {
|
||||
if (!mProgressStyle) {
|
||||
// Custom view
|
||||
int layout = aAlertText.length() > 0 ? R.layout.notification_progress_text : R.layout.notification_progress;
|
||||
|
||||
RemoteViews view = new RemoteViews(GeckoApp.mAppContext.getPackageName(), layout);
|
||||
view.setImageViewResource(R.id.notificationImage, mIcon);
|
||||
view.setTextViewText(R.id.notificationTitle, mTitle);
|
||||
contentView = view;
|
||||
flags |= FLAG_ONGOING_EVENT | FLAG_ONLY_ALERT_ONCE;
|
||||
|
||||
mProgressStyle = true;
|
||||
}
|
||||
|
||||
String text;
|
||||
double percent = 0;
|
||||
if (aProgressMax > 0)
|
||||
percent = ((double)aProgress / (double)aProgressMax);
|
||||
|
||||
if (aAlertText.length() > 0)
|
||||
text = aAlertText;
|
||||
else
|
||||
text = NumberFormat.getPercentInstance().format(percent);
|
||||
|
||||
if (mPrevAlertText.equals(text) && Math.abs(mPrevPercent - percent) < UPDATE_THRESHOLD)
|
||||
return;
|
||||
|
||||
contentView.setTextViewText(R.id.notificationText, text);
|
||||
contentView.setProgressBar(R.id.notificationProgressbar, (int)aProgressMax, (int)aProgress, false);
|
||||
|
||||
// Update the notification
|
||||
mNotificationManager.notify(mId, this);
|
||||
|
||||
mPrevPercent = percent;
|
||||
mPrevAlertText = text;
|
||||
}
|
||||
}
|
@ -1,149 +0,0 @@
|
||||
#filter substitution
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="@ANDROID_PACKAGE_NAME@"
|
||||
android:installLocation="auto"
|
||||
android:versionCode="@ANDROID_VERSION_CODE@"
|
||||
android:versionName="@MOZ_APP_VERSION@"
|
||||
#ifdef MOZ_ANDROID_SHARED_ID
|
||||
android:sharedUserId="@MOZ_ANDROID_SHARED_ID@"
|
||||
#endif
|
||||
>
|
||||
|
||||
<uses-sdk android:minSdkVersion="5"
|
||||
android:targetSdkVersion="11"/>
|
||||
|
||||
<compatible-screens>
|
||||
<!-- all xlarge size screens -->
|
||||
<screen android:screenSize="xlarge" android:screenDensity="ldpi" />
|
||||
<screen android:screenSize="xlarge" android:screenDensity="mdpi" />
|
||||
<screen android:screenSize="xlarge" android:screenDensity="hdpi" />
|
||||
<screen android:screenSize="xlarge" android:screenDensity="xhdpi" />
|
||||
</compatible-screens>
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
|
||||
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||
|
||||
#ifdef MOZ_WEBSMS_BACKEND
|
||||
<!-- WebSMS -->
|
||||
<uses-permission android:name="android.permission.SEND_SMS"/>
|
||||
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
|
||||
<uses-permission android:name="android.permission.WRITE_SMS"/>
|
||||
<uses-permission android:name="android.permission.READ_SMS"/>
|
||||
#endif
|
||||
|
||||
<uses-feature android:name="android.hardware.location" android:required="false"/>
|
||||
<uses-feature android:name="android.hardware.location.gps" android:required="false"/>
|
||||
<uses-feature android:name="android.hardware.touchscreen"/>
|
||||
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-feature android:name="android.hardware.camera" android:required="false"/>
|
||||
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>
|
||||
|
||||
<application android:label="@MOZ_APP_DISPLAYNAME@"
|
||||
android:icon="@drawable/icon"
|
||||
#if MOZILLA_OFFICIAL
|
||||
android:debuggable="false">
|
||||
#else
|
||||
android:debuggable="true">
|
||||
#endif
|
||||
|
||||
<activity android:name="App"
|
||||
android:label="@MOZ_APP_DISPLAYNAME@"
|
||||
android:configChanges="keyboard|keyboardHidden|mcc|mnc"
|
||||
android:windowSoftInputMode="stateUnspecified|adjustResize"
|
||||
android:launchMode="singleTask"
|
||||
android:theme="@style/GreyTheme">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
<!-- Default browser intents -->
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="http" />
|
||||
<data android:scheme="https" />
|
||||
<data android:scheme="about" />
|
||||
<data android:scheme="javascript" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:scheme="file" />
|
||||
<data android:scheme="http" />
|
||||
<data android:scheme="https" />
|
||||
<data android:mimeType="text/html"/>
|
||||
<data android:mimeType="text/plain"/>
|
||||
<data android:mimeType="application/xhtml+xml"/>
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.WEB_SEARCH" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="" />
|
||||
<data android:scheme="http" />
|
||||
<data android:scheme="https" />
|
||||
</intent-filter>
|
||||
|
||||
<!-- For debugging -->
|
||||
<intent-filter>
|
||||
<action android:name="org.mozilla.gecko.DEBUG" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<receiver android:name="NotificationHandler">
|
||||
<intent-filter>
|
||||
<action android:name="org.mozilla.gecko.ACTION_ALERT_CLICK" />
|
||||
<action android:name="org.mozilla.gecko.ACTION_ALERT_CLEAR" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<activity android:name="Restarter"
|
||||
android:process="@ANDROID_PACKAGE_NAME@Restarter"
|
||||
android:theme="@style/GreyTheme"
|
||||
android:excludeFromRecents="true">
|
||||
<intent-filter>
|
||||
<action android:name="org.mozilla.gecko.restart"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
#if MOZ_CRASHREPORTER
|
||||
<activity android:name="CrashReporter"
|
||||
android:label="@string/crash_reporter_title"
|
||||
android:icon="@drawable/crash_reporter"
|
||||
android:excludeFromRecents="true">
|
||||
<intent-filter>
|
||||
<action android:name="org.mozilla.gecko.reportCrash" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
#endif
|
||||
|
||||
<activity android:name="LauncherShortcuts"
|
||||
android:label="@string/launcher_shortcuts_title"
|
||||
android:theme="@android:style/Theme.Translucent">
|
||||
<!-- This intent-filter allows your shortcuts to be created in the launcher. -->
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.CREATE_SHORTCUT" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="org.mozilla.gecko.VideoPlayer"
|
||||
android:configChanges="keyboard|keyboardHidden|mcc|mnc|orientation"
|
||||
android:theme="@android:style/Theme.NoTitleBar" >
|
||||
<intent-filter>
|
||||
<action android:name="org.mozilla.gecko.PLAY_VIDEO" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
@ -1,19 +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/. */
|
||||
|
||||
#filter substitution
|
||||
package @ANDROID_PACKAGE_NAME@;
|
||||
|
||||
import org.mozilla.gecko.GeckoApp;
|
||||
|
||||
public class App extends GeckoApp {
|
||||
public String getPackageName() {
|
||||
return "@ANDROID_PACKAGE_NAME@";
|
||||
}
|
||||
public String getContentProcessName() {
|
||||
return "@MOZ_CHILD_PROCESS_NAME@";
|
||||
}
|
||||
};
|
||||
|
@ -1,311 +0,0 @@
|
||||
/* -*- Mode: Java; 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/. */
|
||||
|
||||
#filter substitution
|
||||
package @ANDROID_PACKAGE_NAME@;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.FileChannel;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
|
||||
import org.mozilla.gecko.R;
|
||||
|
||||
public class CrashReporter extends Activity
|
||||
{
|
||||
private static final String LOGTAG = "GeckoCrashReporter";
|
||||
|
||||
private static final String PASSED_MINI_DUMP_KEY = "minidumpPath";
|
||||
private static final String MINI_DUMP_PATH_KEY = "upload_file_minidump";
|
||||
private static final String PAGE_URL_KEY = "URL";
|
||||
private static final String NOTES_KEY = "Notes";
|
||||
private static final String SERVER_URL_KEY = "ServerURL";
|
||||
|
||||
private static final String CRASH_REPORT_SUFFIX = "/mozilla/Crash Reports/";
|
||||
private static final String PENDING_SUFFIX = CRASH_REPORT_SUFFIX + "pending";
|
||||
private static final String SUBMITTED_SUFFIX = CRASH_REPORT_SUFFIX + "submitted";
|
||||
|
||||
private Handler mHandler;
|
||||
private ProgressDialog mProgressDialog;
|
||||
private File mPendingMinidumpFile;
|
||||
private File mPendingExtrasFile;
|
||||
private HashMap<String, String> mExtrasStringMap;
|
||||
|
||||
private boolean moveFile(File inFile, File outFile) {
|
||||
Log.i(LOGTAG, "moving " + inFile + " to " + outFile);
|
||||
if (inFile.renameTo(outFile))
|
||||
return true;
|
||||
try {
|
||||
outFile.createNewFile();
|
||||
Log.i(LOGTAG, "couldn't rename minidump file");
|
||||
// so copy it instead
|
||||
FileChannel inChannel = new FileInputStream(inFile).getChannel();
|
||||
FileChannel outChannel = new FileOutputStream(outFile).getChannel();
|
||||
long transferred = inChannel.transferTo(0, inChannel.size(), outChannel);
|
||||
inChannel.close();
|
||||
outChannel.close();
|
||||
|
||||
if (transferred > 0)
|
||||
inFile.delete();
|
||||
} catch (Exception e) {
|
||||
Log.e(LOGTAG, "exception while copying minidump file: ", e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void doFinish() {
|
||||
if (mHandler != null) {
|
||||
mHandler.post(new Runnable() {
|
||||
public void run() {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
try {
|
||||
if (mProgressDialog.isShowing()) {
|
||||
mProgressDialog.dismiss();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(LOGTAG, "exception while closing progress dialog: ", e);
|
||||
}
|
||||
super.finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
// mHandler is created here so runnables can be run on the main thread
|
||||
mHandler = new Handler();
|
||||
setContentView(R.layout.crash_reporter);
|
||||
mProgressDialog = new ProgressDialog(this);
|
||||
mProgressDialog.setMessage(getString(R.string.sending_crash_report));
|
||||
|
||||
final Button restartButton = (Button) findViewById(R.id.restart);
|
||||
final Button closeButton = (Button) findViewById(R.id.close);
|
||||
String passedMinidumpPath = getIntent().getStringExtra(PASSED_MINI_DUMP_KEY);
|
||||
File passedMinidumpFile = new File(passedMinidumpPath);
|
||||
File pendingDir = new File(getFilesDir(), PENDING_SUFFIX);
|
||||
pendingDir.mkdirs();
|
||||
mPendingMinidumpFile = new File(pendingDir, passedMinidumpFile.getName());
|
||||
moveFile(passedMinidumpFile, mPendingMinidumpFile);
|
||||
|
||||
File extrasFile = new File(passedMinidumpPath.replaceAll(".dmp", ".extra"));
|
||||
mPendingExtrasFile = new File(pendingDir, extrasFile.getName());
|
||||
moveFile(extrasFile, mPendingExtrasFile);
|
||||
|
||||
mExtrasStringMap = new HashMap<String, String>();
|
||||
readStringsFromFile(mPendingExtrasFile.getPath(), mExtrasStringMap);
|
||||
}
|
||||
|
||||
private void backgroundSendReport() {
|
||||
final CheckBox sendReportCheckbox = (CheckBox) findViewById(R.id.send_report);
|
||||
if (!sendReportCheckbox.isChecked()) {
|
||||
doFinish();
|
||||
return;
|
||||
}
|
||||
|
||||
mProgressDialog.show();
|
||||
new Thread(new Runnable() {
|
||||
public void run() {
|
||||
sendReport(mPendingMinidumpFile, mExtrasStringMap, mPendingExtrasFile);
|
||||
}
|
||||
}, "CrashReporter Thread").start();
|
||||
}
|
||||
|
||||
public void onCloseClick(View v) { // bound via crash_reporter.xml
|
||||
backgroundSendReport();
|
||||
}
|
||||
|
||||
public void onRestartClick(View v) { // bound via crash_reporter.xml
|
||||
doRestart();
|
||||
backgroundSendReport();
|
||||
}
|
||||
|
||||
private boolean readStringsFromFile(String filePath, Map<String, String> stringMap) {
|
||||
try {
|
||||
BufferedReader reader = new BufferedReader(new FileReader(filePath));
|
||||
return readStringsFromReader(reader, stringMap);
|
||||
} catch (Exception e) {
|
||||
Log.e(LOGTAG, "exception while reading strings: ", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean readStringsFromReader(BufferedReader reader, Map<String, String> stringMap) throws IOException {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
int equalsPos = -1;
|
||||
if ((equalsPos = line.indexOf('=')) != -1) {
|
||||
String key = line.substring(0, equalsPos);
|
||||
String val = unescape(line.substring(equalsPos + 1));
|
||||
stringMap.put(key, val);
|
||||
}
|
||||
}
|
||||
reader.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
private String generateBoundary() {
|
||||
// Generate some random numbers to fill out the boundary
|
||||
int r0 = (int)((double)Integer.MAX_VALUE * Math.random());
|
||||
int r1 = (int)((double)Integer.MAX_VALUE * Math.random());
|
||||
return String.format("---------------------------%08X%08X", r0, r1);
|
||||
}
|
||||
|
||||
private void sendPart(OutputStream os, String boundary, String name, String data) {
|
||||
try {
|
||||
os.write(("--" + boundary + "\r\n" +
|
||||
"Content-Disposition: form-data; name=\"" + name + "\"\r\n" +
|
||||
"\r\n" +
|
||||
data + "\r\n"
|
||||
).getBytes());
|
||||
} catch (Exception ex) {
|
||||
Log.e(LOGTAG, "Exception when sending \"" + name + "\"", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendFile(OutputStream os, String boundary, String name, File file) throws IOException {
|
||||
os.write(("--" + boundary + "\r\n" +
|
||||
"Content-Disposition: form-data; name=\"" + name + "\"; " +
|
||||
"filename=\"" + file.getName() + "\"\r\n" +
|
||||
"Content-Type: application/octet-stream\r\n" +
|
||||
"\r\n"
|
||||
).getBytes());
|
||||
FileChannel fc = new FileInputStream(file).getChannel();
|
||||
fc.transferTo(0, fc.size(), Channels.newChannel(os));
|
||||
fc.close();
|
||||
}
|
||||
|
||||
private void sendReport(File minidumpFile, Map<String, String> extras, File extrasFile) {
|
||||
Log.i(LOGTAG, "sendReport: " + minidumpFile.getPath());
|
||||
final CheckBox includeURLCheckbox = (CheckBox) findViewById(R.id.include_url);
|
||||
|
||||
String spec = extras.get(SERVER_URL_KEY);
|
||||
if (spec == null) {
|
||||
doFinish();
|
||||
return;
|
||||
}
|
||||
|
||||
Log.i(LOGTAG, "server url: " + spec);
|
||||
try {
|
||||
URL url = new URL(spec);
|
||||
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
|
||||
conn.setRequestMethod("POST");
|
||||
String boundary = generateBoundary();
|
||||
conn.setDoOutput(true);
|
||||
conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
|
||||
|
||||
OutputStream os = conn.getOutputStream();
|
||||
for (String key : extras.keySet()) {
|
||||
if (key.equals(PAGE_URL_KEY)) {
|
||||
if (includeURLCheckbox.isChecked())
|
||||
sendPart(os, boundary, key, extras.get(key));
|
||||
} else if (!key.equals(SERVER_URL_KEY) && !key.equals(NOTES_KEY)) {
|
||||
sendPart(os, boundary, key, extras.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
// Add some extra information to notes so its displayed by
|
||||
// crash-stats.mozilla.org. Remove this when bug 607942 is fixed.
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(extras.containsKey(NOTES_KEY) ? extras.get(NOTES_KEY) + "\n" : "");
|
||||
if (@MOZ_MIN_CPU_VERSION@ < 7)
|
||||
sb.append("nothumb Build\n");
|
||||
sb.append(Build.MANUFACTURER).append(' ')
|
||||
.append(Build.MODEL).append('\n')
|
||||
.append(Build.FINGERPRINT);
|
||||
sendPart(os, boundary, NOTES_KEY, sb.toString());
|
||||
|
||||
sendPart(os, boundary, "Min_ARM_Version", "@MOZ_MIN_CPU_VERSION@");
|
||||
sendPart(os, boundary, "Android_Manufacturer", Build.MANUFACTURER);
|
||||
sendPart(os, boundary, "Android_Model", Build.MODEL);
|
||||
sendPart(os, boundary, "Android_Board", Build.BOARD);
|
||||
sendPart(os, boundary, "Android_Brand", Build.BRAND);
|
||||
sendPart(os, boundary, "Android_Device", Build.DEVICE);
|
||||
sendPart(os, boundary, "Android_Display", Build.DISPLAY);
|
||||
sendPart(os, boundary, "Android_Fingerprint", Build.FINGERPRINT);
|
||||
sendPart(os, boundary, "Android_CPU_ABI", Build.CPU_ABI);
|
||||
if (Build.VERSION.SDK_INT >= 8) {
|
||||
try {
|
||||
sendPart(os, boundary, "Android_CPU_ABI2", Build.CPU_ABI2);
|
||||
sendPart(os, boundary, "Android_Hardware", Build.HARDWARE);
|
||||
} catch (Exception ex) {
|
||||
Log.e(LOGTAG, "Exception while sending SDK version 8 keys", ex);
|
||||
}
|
||||
}
|
||||
sendPart(os, boundary, "Android_Version", Build.VERSION.SDK_INT + " (" + Build.VERSION.CODENAME + ")");
|
||||
|
||||
sendFile(os, boundary, MINI_DUMP_PATH_KEY, minidumpFile);
|
||||
os.write(("\r\n--" + boundary + "--\r\n").getBytes());
|
||||
os.flush();
|
||||
os.close();
|
||||
BufferedReader br = new BufferedReader(
|
||||
new InputStreamReader(conn.getInputStream()));
|
||||
HashMap<String, String> responseMap = new HashMap<String, String>();
|
||||
readStringsFromReader(br, responseMap);
|
||||
|
||||
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||
File submittedDir = new File(getFilesDir(),
|
||||
SUBMITTED_SUFFIX);
|
||||
submittedDir.mkdirs();
|
||||
minidumpFile.delete();
|
||||
extrasFile.delete();
|
||||
String crashid = responseMap.get("CrashID");
|
||||
File file = new File(submittedDir, crashid + ".txt");
|
||||
FileOutputStream fos = new FileOutputStream(file);
|
||||
fos.write("Crash ID: ".getBytes());
|
||||
fos.write(crashid.getBytes());
|
||||
fos.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(LOGTAG, "exception during send: ", e);
|
||||
}
|
||||
|
||||
doFinish();
|
||||
}
|
||||
|
||||
private void doRestart() {
|
||||
try {
|
||||
String action = "android.intent.action.MAIN";
|
||||
Intent intent = new Intent(action);
|
||||
intent.setClassName("@ANDROID_PACKAGE_NAME@",
|
||||
"@ANDROID_PACKAGE_NAME@.App");
|
||||
Log.i(LOGTAG, intent.toString());
|
||||
startActivity(intent);
|
||||
} catch (Exception e) {
|
||||
Log.e(LOGTAG, "error while trying to restart", e);
|
||||
}
|
||||
}
|
||||
|
||||
private String unescape(String string) {
|
||||
return string.replaceAll("\\\\\\\\", "\\").replaceAll("\\\\n", "\n").replaceAll("\\\\t", "\t");
|
||||
}
|
||||
}
|
@ -1,858 +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 java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
import java.nio.*;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.util.concurrent.*;
|
||||
import java.lang.reflect.*;
|
||||
|
||||
import android.os.*;
|
||||
import android.app.*;
|
||||
import android.text.*;
|
||||
import android.view.*;
|
||||
import android.view.inputmethod.*;
|
||||
import android.content.*;
|
||||
import android.content.res.*;
|
||||
import android.graphics.*;
|
||||
import android.widget.*;
|
||||
import android.hardware.*;
|
||||
|
||||
import android.util.*;
|
||||
import android.net.*;
|
||||
import android.database.*;
|
||||
import android.provider.*;
|
||||
import android.content.pm.*;
|
||||
import android.content.pm.PackageManager.*;
|
||||
import dalvik.system.*;
|
||||
|
||||
abstract public class GeckoApp
|
||||
extends Activity
|
||||
{
|
||||
private static final String LOG_FILE_NAME = "GeckoApp";
|
||||
|
||||
public static final String ACTION_ALERT_CLICK = "org.mozilla.gecko.ACTION_ALERT_CLICK";
|
||||
public static final String ACTION_ALERT_CLEAR = "org.mozilla.gecko.ACTION_ALERT_CLEAR";
|
||||
public static final String ACTION_WEBAPP = "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 AbsoluteLayout mainLayout;
|
||||
public static GeckoSurfaceView surfaceView;
|
||||
public static SurfaceView cameraView;
|
||||
public static GeckoApp mAppContext;
|
||||
public static boolean mFullscreen = false;
|
||||
public static File sGREDir = null;
|
||||
static Thread mLibLoadThread = null;
|
||||
public Handler mMainHandler;
|
||||
private IntentFilter mConnectivityFilter;
|
||||
private BroadcastReceiver mConnectivityReceiver;
|
||||
private BroadcastReceiver mBatteryReceiver;
|
||||
|
||||
enum LaunchState {PreLaunch, Launching, WaitForDebugger,
|
||||
Launched, GeckoRunning, GeckoExiting};
|
||||
private static LaunchState sLaunchState = LaunchState.PreLaunch;
|
||||
private static boolean sTryCatchAttached = false;
|
||||
|
||||
|
||||
static boolean checkLaunchState(LaunchState checkState) {
|
||||
synchronized(sLaunchState) {
|
||||
return sLaunchState == checkState;
|
||||
}
|
||||
}
|
||||
|
||||
static void setLaunchState(LaunchState setState) {
|
||||
synchronized(sLaunchState) {
|
||||
sLaunchState = setState;
|
||||
}
|
||||
}
|
||||
|
||||
// if mLaunchState is equal to checkState this sets mLaunchState to setState
|
||||
// and return true. Otherwise we return false.
|
||||
static boolean checkAndSetLaunchState(LaunchState checkState, LaunchState setState) {
|
||||
synchronized(sLaunchState) {
|
||||
if (sLaunchState != checkState)
|
||||
return false;
|
||||
sLaunchState = setState;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void showErrorDialog(String message)
|
||||
{
|
||||
new AlertDialog.Builder(this)
|
||||
.setMessage(message)
|
||||
.setCancelable(false)
|
||||
.setPositiveButton(R.string.exit_label,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog,
|
||||
int id)
|
||||
{
|
||||
GeckoApp.this.finish();
|
||||
System.exit(0);
|
||||
}
|
||||
}).show();
|
||||
}
|
||||
|
||||
public static final String PLUGIN_ACTION = "android.webkit.PLUGIN";
|
||||
|
||||
/**
|
||||
* A plugin that wish to be loaded in the WebView must provide this permission
|
||||
* in their AndroidManifest.xml.
|
||||
*/
|
||||
public static final String PLUGIN_PERMISSION = "android.webkit.permission.PLUGIN";
|
||||
|
||||
private static final String LOGTAG = "PluginManager";
|
||||
|
||||
private static final String PLUGIN_SYSTEM_LIB = "/system/lib/plugins/";
|
||||
|
||||
private static final String PLUGIN_TYPE = "type";
|
||||
private static final String TYPE_NATIVE = "native";
|
||||
public ArrayList<PackageInfo> mPackageInfoCache = new ArrayList<PackageInfo>();
|
||||
|
||||
String[] getPluginDirectories() {
|
||||
|
||||
ArrayList<String> directories = new ArrayList<String>();
|
||||
PackageManager pm = this.mAppContext.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, "Ignore bad plugin");
|
||||
continue;
|
||||
}
|
||||
|
||||
Log.w(LOGTAG, "Loading plugin: " + serviceInfo.packageName);
|
||||
|
||||
|
||||
// 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, "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, "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, "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, "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 type defined");
|
||||
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()]);
|
||||
}
|
||||
|
||||
Class<?> getPluginClass(String packageName, String className)
|
||||
throws NameNotFoundException, ClassNotFoundException {
|
||||
Context pluginContext = this.mAppContext.createPackageContext(packageName,
|
||||
Context.CONTEXT_INCLUDE_CODE |
|
||||
Context.CONTEXT_IGNORE_SECURITY);
|
||||
ClassLoader pluginCL = pluginContext.getClassLoader();
|
||||
return pluginCL.loadClass(className);
|
||||
}
|
||||
|
||||
// Returns true when the intent is going to be handled by gecko launch
|
||||
boolean launch(Intent intent)
|
||||
{
|
||||
if (!checkAndSetLaunchState(LaunchState.Launching, LaunchState.Launched))
|
||||
return false;
|
||||
|
||||
if (intent == null)
|
||||
intent = getIntent();
|
||||
final Intent i = intent;
|
||||
new Thread() {
|
||||
public void run() {
|
||||
try {
|
||||
if (mLibLoadThread != null)
|
||||
mLibLoadThread.join();
|
||||
} catch (InterruptedException ie) {}
|
||||
|
||||
// Show the URL we are about to load, if the intent has one
|
||||
if (Intent.ACTION_VIEW.equals(i.getAction())) {
|
||||
surfaceView.mSplashURL = i.getDataString();
|
||||
}
|
||||
surfaceView.drawSplashScreen();
|
||||
|
||||
// unpack files in the components directory
|
||||
try {
|
||||
unpackComponents();
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
Log.e(LOG_FILE_NAME, "error unpacking components", fnfe);
|
||||
Looper.prepare();
|
||||
showErrorDialog(getString(R.string.error_loading_file));
|
||||
Looper.loop();
|
||||
return;
|
||||
} catch (IOException ie) {
|
||||
Log.e(LOG_FILE_NAME, "error unpacking components", ie);
|
||||
String msg = ie.getMessage();
|
||||
Looper.prepare();
|
||||
if (msg != null && msg.equalsIgnoreCase("No space left on device"))
|
||||
showErrorDialog(getString(R.string.no_space_to_start_error));
|
||||
else
|
||||
showErrorDialog(getString(R.string.error_loading_file));
|
||||
Looper.loop();
|
||||
return;
|
||||
}
|
||||
|
||||
// and then fire us up
|
||||
try {
|
||||
String env = i.getStringExtra("env0");
|
||||
GeckoAppShell.runGecko(getApplication().getPackageResourcePath(),
|
||||
i.getStringExtra("args"),
|
||||
i.getDataString());
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_FILE_NAME, "top level exception", e);
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
e.printStackTrace(pw);
|
||||
pw.flush();
|
||||
GeckoAppShell.reportJavaCrash(sw.toString());
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Called when the activity is first created. */
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
mAppContext = this;
|
||||
mMainHandler = new Handler();
|
||||
|
||||
if (!sTryCatchAttached) {
|
||||
sTryCatchAttached = true;
|
||||
mMainHandler.post(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
Looper.loop();
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_FILE_NAME, "top level exception", e);
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
e.printStackTrace(pw);
|
||||
pw.flush();
|
||||
GeckoAppShell.reportJavaCrash(sw.toString());
|
||||
}
|
||||
// resetting this is kinda pointless, but oh well
|
||||
sTryCatchAttached = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
SharedPreferences settings = getPreferences(Activity.MODE_PRIVATE);
|
||||
String localeCode = settings.getString(getPackageName() + ".locale", "");
|
||||
if (localeCode != null && localeCode.length() > 0)
|
||||
GeckoAppShell.setSelectedLocale(localeCode);
|
||||
|
||||
Log.i(LOG_FILE_NAME, "create");
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
if (sGREDir == null)
|
||||
sGREDir = new File(this.getApplicationInfo().dataDir);
|
||||
|
||||
getWindow().setFlags(mFullscreen ?
|
||||
WindowManager.LayoutParams.FLAG_FULLSCREEN : 0,
|
||||
WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
|
||||
if (cameraView == null) {
|
||||
cameraView = new SurfaceView(this);
|
||||
cameraView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
|
||||
}
|
||||
|
||||
if (surfaceView == null)
|
||||
surfaceView = new GeckoSurfaceView(this);
|
||||
else
|
||||
mainLayout.removeAllViews();
|
||||
|
||||
mainLayout = new AbsoluteLayout(this);
|
||||
mainLayout.addView(surfaceView,
|
||||
new AbsoluteLayout.LayoutParams(AbsoluteLayout.LayoutParams.MATCH_PARENT, // level 8
|
||||
AbsoluteLayout.LayoutParams.MATCH_PARENT,
|
||||
0,
|
||||
0));
|
||||
|
||||
setContentView(mainLayout,
|
||||
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
|
||||
ViewGroup.LayoutParams.FILL_PARENT));
|
||||
|
||||
mConnectivityFilter = new IntentFilter();
|
||||
mConnectivityFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
|
||||
mConnectivityReceiver = new GeckoConnectivityReceiver();
|
||||
|
||||
IntentFilter batteryFilter = new IntentFilter();
|
||||
batteryFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
|
||||
mBatteryReceiver = new GeckoBatteryManager();
|
||||
registerReceiver(mBatteryReceiver, batteryFilter);
|
||||
|
||||
if (SmsManager.getInstance() != null) {
|
||||
SmsManager.getInstance().start();
|
||||
}
|
||||
|
||||
GeckoNetworkManager.getInstance().init();
|
||||
|
||||
if (!checkAndSetLaunchState(LaunchState.PreLaunch,
|
||||
LaunchState.Launching))
|
||||
return;
|
||||
|
||||
checkAndLaunchUpdate();
|
||||
mLibLoadThread = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
// 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();
|
||||
GeckoAppShell.loadGeckoLibs(
|
||||
getApplication().getPackageResourcePath());
|
||||
Locale.setDefault(locale);
|
||||
Resources res = getBaseContext().getResources();
|
||||
Configuration config = res.getConfiguration();
|
||||
config.locale = locale;
|
||||
res.updateConfiguration(config, res.getDisplayMetrics());
|
||||
}});
|
||||
mLibLoadThread.start();
|
||||
}
|
||||
|
||||
public void enableCameraView() {
|
||||
// Some phones (eg. nexus S) need at least a 8x16 preview size
|
||||
mainLayout.addView(cameraView, new AbsoluteLayout.LayoutParams(8, 16, 0, 0));
|
||||
}
|
||||
|
||||
public void disableCameraView() {
|
||||
mainLayout.removeView(cameraView);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
if (checkLaunchState(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;
|
||||
}
|
||||
final String action = intent.getAction();
|
||||
if (ACTION_DEBUG.equals(action) &&
|
||||
checkAndSetLaunchState(LaunchState.Launching, LaunchState.WaitForDebugger)) {
|
||||
|
||||
mMainHandler.postDelayed(new Runnable() {
|
||||
public void run() {
|
||||
Log.i(LOG_FILE_NAME, "Launching from debug intent after 5s wait");
|
||||
setLaunchState(LaunchState.Launching);
|
||||
launch(null);
|
||||
}
|
||||
}, 1000 * 5 /* 5 seconds */);
|
||||
Log.i(LOG_FILE_NAME, "Intent : ACTION_DEBUG - waiting 5s before launching");
|
||||
return;
|
||||
}
|
||||
if (checkLaunchState(LaunchState.WaitForDebugger) || launch(intent))
|
||||
return;
|
||||
|
||||
if (Intent.ACTION_MAIN.equals(action)) {
|
||||
Log.i(LOG_FILE_NAME, "Intent : ACTION_MAIN");
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(""));
|
||||
}
|
||||
else if (Intent.ACTION_VIEW.equals(action)) {
|
||||
String uri = intent.getDataString();
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(uri));
|
||||
Log.i(LOG_FILE_NAME,"onNewIntent: "+uri);
|
||||
}
|
||||
else if (ACTION_WEBAPP.equals(action)) {
|
||||
String uri = intent.getStringExtra("args");
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(uri));
|
||||
Log.i(LOG_FILE_NAME,"Intent : WEBAPP - " + uri);
|
||||
}
|
||||
else if (ACTION_BOOKMARK.equals(action)) {
|
||||
String args = intent.getStringExtra("args");
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(args));
|
||||
Log.i(LOG_FILE_NAME,"Intent : BOOKMARK - " + args);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause()
|
||||
{
|
||||
Log.i(LOG_FILE_NAME, "pause");
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(GeckoEvent.ACTIVITY_PAUSING));
|
||||
// The user is navigating away from this activity, but nothing
|
||||
// has come to the foreground yet; for Gecko, we may want to
|
||||
// stop repainting, for example.
|
||||
|
||||
// Whatever we do here should be fast, because we're blocking
|
||||
// the next activity from showing up until we finish.
|
||||
|
||||
// onPause will be followed by either onResume or onStop.
|
||||
super.onPause();
|
||||
|
||||
unregisterReceiver(mConnectivityReceiver);
|
||||
GeckoNetworkManager.getInstance().stop();
|
||||
GeckoScreenOrientationListener.getInstance().stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume()
|
||||
{
|
||||
Log.i(LOG_FILE_NAME, "resume");
|
||||
if (checkLaunchState(LaunchState.GeckoRunning))
|
||||
GeckoAppShell.onResume();
|
||||
// After an onPause, the activity is back in the foreground.
|
||||
// Undo whatever we did in onPause.
|
||||
super.onResume();
|
||||
|
||||
// Just in case. Normally we start in onNewIntent
|
||||
if (checkLaunchState(LaunchState.PreLaunch) ||
|
||||
checkLaunchState(LaunchState.Launching))
|
||||
onNewIntent(getIntent());
|
||||
|
||||
registerReceiver(mConnectivityReceiver, mConnectivityFilter);
|
||||
GeckoNetworkManager.getInstance().start();
|
||||
GeckoScreenOrientationListener.getInstance().start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop()
|
||||
{
|
||||
Log.i(LOG_FILE_NAME, "stop");
|
||||
// We're about to be stopped, potentially in preparation for
|
||||
// being destroyed. We're killable after this point -- as I
|
||||
// understand it, in extreme cases the process can be terminated
|
||||
// without going through onDestroy.
|
||||
//
|
||||
// We might also get an onRestart after this; not sure what
|
||||
// that would mean for Gecko if we were to kill it here.
|
||||
// Instead, what we should do here is save prefs, session,
|
||||
// etc., and generally mark the profile as 'clean', and then
|
||||
// dirty it again if we get an onResume.
|
||||
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(GeckoEvent.ACTIVITY_STOPPING));
|
||||
super.onStop();
|
||||
GeckoAppShell.putChildInBackground();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestart()
|
||||
{
|
||||
Log.i(LOG_FILE_NAME, "restart");
|
||||
GeckoAppShell.putChildInForeground();
|
||||
super.onRestart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart()
|
||||
{
|
||||
Log.i(LOG_FILE_NAME, "start");
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(GeckoEvent.ACTIVITY_START));
|
||||
super.onStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy()
|
||||
{
|
||||
Log.i(LOG_FILE_NAME, "destroy");
|
||||
|
||||
// Tell Gecko to shutting down; we'll end up calling System.exit()
|
||||
// in onXreExit.
|
||||
if (isFinishing())
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(GeckoEvent.ACTIVITY_SHUTDOWN));
|
||||
|
||||
if (SmsManager.getInstance() != null) {
|
||||
SmsManager.getInstance().stop();
|
||||
if (isFinishing())
|
||||
SmsManager.getInstance().shutdown();
|
||||
}
|
||||
|
||||
GeckoNetworkManager.getInstance().stop();
|
||||
GeckoScreenOrientationListener.getInstance().stop();
|
||||
|
||||
super.onDestroy();
|
||||
|
||||
unregisterReceiver(mBatteryReceiver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(android.content.res.Configuration newConfig)
|
||||
{
|
||||
Log.i(LOG_FILE_NAME, "configuration changed");
|
||||
// nothing, just ignore
|
||||
super.onConfigurationChanged(newConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLowMemory()
|
||||
{
|
||||
Log.e(LOG_FILE_NAME, "low memory");
|
||||
if (checkLaunchState(LaunchState.GeckoRunning))
|
||||
GeckoAppShell.onLowMemory();
|
||||
super.onLowMemory();
|
||||
}
|
||||
|
||||
abstract public String getPackageName();
|
||||
abstract public String getContentProcessName();
|
||||
|
||||
protected void unpackComponents()
|
||||
throws IOException, FileNotFoundException
|
||||
{
|
||||
File applicationPackage = new File(getApplication().getPackageResourcePath());
|
||||
File componentsDir = new File(sGREDir, "components");
|
||||
if (componentsDir.lastModified() == applicationPackage.lastModified())
|
||||
return;
|
||||
|
||||
componentsDir.mkdir();
|
||||
componentsDir.setLastModified(applicationPackage.lastModified());
|
||||
|
||||
GeckoAppShell.killAnyZombies();
|
||||
|
||||
ZipFile zip = new ZipFile(applicationPackage);
|
||||
|
||||
byte[] buf = new byte[32768];
|
||||
try {
|
||||
if (unpackFile(zip, buf, null, "removed-files"))
|
||||
removeFiles();
|
||||
} catch (Exception ex) {
|
||||
// This file may not be there, so just log any errors and move on
|
||||
Log.w(LOG_FILE_NAME, "error removing files", ex);
|
||||
}
|
||||
|
||||
// copy any .xpi file into an extensions/ directory
|
||||
Enumeration<? extends ZipEntry> zipEntries = zip.entries();
|
||||
while (zipEntries.hasMoreElements()) {
|
||||
ZipEntry entry = zipEntries.nextElement();
|
||||
if (entry.getName().startsWith("extensions/") && entry.getName().endsWith(".xpi")) {
|
||||
Log.i("GeckoAppJava", "installing extension : " + entry.getName());
|
||||
unpackFile(zip, buf, entry, entry.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void removeFiles() throws IOException {
|
||||
BufferedReader reader = new BufferedReader(
|
||||
new FileReader(new File(sGREDir, "removed-files")));
|
||||
try {
|
||||
for (String removedFileName = reader.readLine();
|
||||
removedFileName != null; removedFileName = reader.readLine()) {
|
||||
File removedFile = new File(sGREDir, removedFileName);
|
||||
if (removedFile.exists())
|
||||
removedFile.delete();
|
||||
}
|
||||
} finally {
|
||||
reader.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean unpackFile(ZipFile zip, byte[] buf, ZipEntry fileEntry,
|
||||
String name)
|
||||
throws IOException, FileNotFoundException
|
||||
{
|
||||
if (fileEntry == null)
|
||||
fileEntry = zip.getEntry(name);
|
||||
if (fileEntry == null)
|
||||
throw new FileNotFoundException("Can't find " + name + " in " +
|
||||
zip.getName());
|
||||
|
||||
File outFile = new File(sGREDir, name);
|
||||
if (outFile.lastModified() == fileEntry.getTime() &&
|
||||
outFile.length() == fileEntry.getSize())
|
||||
return false;
|
||||
|
||||
File dir = outFile.getParentFile();
|
||||
if (!dir.exists())
|
||||
dir.mkdirs();
|
||||
|
||||
InputStream fileStream;
|
||||
fileStream = zip.getInputStream(fileEntry);
|
||||
|
||||
OutputStream outStream = new FileOutputStream(outFile);
|
||||
|
||||
while (fileStream.available() > 0) {
|
||||
int read = fileStream.read(buf, 0, buf.length);
|
||||
outStream.write(buf, 0, read);
|
||||
}
|
||||
|
||||
fileStream.close();
|
||||
outStream.close();
|
||||
outFile.setLastModified(fileEntry.getTime());
|
||||
return true;
|
||||
}
|
||||
|
||||
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() {
|
||||
try {
|
||||
String action = "org.mozilla.gecko.restart";
|
||||
Intent intent = new Intent(action);
|
||||
intent.setClassName(getPackageName(),
|
||||
getPackageName() + ".Restarter");
|
||||
addEnvToIntent(intent);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
|
||||
Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
|
||||
Log.i(LOG_FILE_NAME, intent.toString());
|
||||
GeckoAppShell.killAnyZombies();
|
||||
startActivity(intent);
|
||||
} catch (Exception e) {
|
||||
Log.i(LOG_FILE_NAME, "error doing restart", e);
|
||||
}
|
||||
finish();
|
||||
// Give the restart process time to start before we die
|
||||
GeckoAppShell.waitForAnotherGeckoProc();
|
||||
}
|
||||
|
||||
public void handleNotification(String action, String alertName, String alertCookie) {
|
||||
GeckoAppShell.handleNotification(action, alertName, alertCookie);
|
||||
}
|
||||
|
||||
private void checkAndLaunchUpdate() {
|
||||
Log.i(LOG_FILE_NAME, "Checking for an update");
|
||||
|
||||
int statusCode = 8; // UNEXPECTED_ERROR
|
||||
File baseUpdateDir = null;
|
||||
if (Build.VERSION.SDK_INT >= 8)
|
||||
baseUpdateDir = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS);
|
||||
else
|
||||
baseUpdateDir = new File(Environment.getExternalStorageDirectory().getPath(), "download");
|
||||
|
||||
File updateDir = new File(new File(baseUpdateDir, "updates"),"0");
|
||||
|
||||
File updateFile = new File(updateDir, "update.apk");
|
||||
File statusFile = new File(updateDir, "update.status");
|
||||
|
||||
if (!statusFile.exists() || !readUpdateStatus(statusFile).equals("pending"))
|
||||
return;
|
||||
|
||||
if (!updateFile.exists())
|
||||
return;
|
||||
|
||||
Log.i(LOG_FILE_NAME, "Update is available!");
|
||||
|
||||
// Launch APK
|
||||
File updateFileToRun = new File(updateDir, getPackageName() + "-update.apk");
|
||||
try {
|
||||
if (updateFile.renameTo(updateFileToRun)) {
|
||||
String amCmd = "/system/bin/am start -a android.intent.action.VIEW " +
|
||||
"-n com.android.packageinstaller/.PackageInstallerActivity -d file://" +
|
||||
updateFileToRun.getPath();
|
||||
Log.i(LOG_FILE_NAME, amCmd);
|
||||
Runtime.getRuntime().exec(amCmd);
|
||||
statusCode = 0; // OK
|
||||
} else {
|
||||
Log.i(LOG_FILE_NAME, "Cannot rename the update file!");
|
||||
statusCode = 7; // WRITE_ERROR
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.i(LOG_FILE_NAME, "error launching installer to update", e);
|
||||
}
|
||||
|
||||
// Update the status file
|
||||
String status = statusCode == 0 ? "succeeded\n" : "failed: "+ statusCode + "\n";
|
||||
|
||||
OutputStream outStream;
|
||||
try {
|
||||
byte[] buf = status.getBytes("UTF-8");
|
||||
outStream = new FileOutputStream(statusFile);
|
||||
outStream.write(buf, 0, buf.length);
|
||||
outStream.close();
|
||||
} catch (Exception e) {
|
||||
Log.i(LOG_FILE_NAME, "error writing status file", e);
|
||||
}
|
||||
|
||||
if (statusCode == 0)
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
private String readUpdateStatus(File statusFile) {
|
||||
String status = "";
|
||||
try {
|
||||
BufferedReader reader = new BufferedReader(new FileReader(statusFile));
|
||||
status = reader.readLine();
|
||||
reader.close();
|
||||
} catch (Exception e) {
|
||||
Log.i(LOG_FILE_NAME, "error reading update status", e);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static final int FILE_PICKER_REQUEST = 1;
|
||||
|
||||
private SynchronousQueue<String> mFilePickerResult = new SynchronousQueue();
|
||||
public String showFilePicker(String aMimeType) {
|
||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
intent.setType(aMimeType);
|
||||
GeckoApp.this.
|
||||
startActivityForResult(
|
||||
Intent.createChooser(intent, getString(R.string.choose_file)),
|
||||
FILE_PICKER_REQUEST);
|
||||
String filePickerResult = "";
|
||||
|
||||
try {
|
||||
while (null == (filePickerResult = mFilePickerResult.poll(1, TimeUnit.MILLISECONDS))) {
|
||||
Log.i("GeckoApp", "processing events from showFilePicker ");
|
||||
GeckoAppShell.processNextNativeEvent();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
Log.i(LOG_FILE_NAME, "showing file picker ", e);
|
||||
}
|
||||
|
||||
return filePickerResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode,
|
||||
Intent data) {
|
||||
String filePickerResult = "";
|
||||
if (data != null && resultCode == RESULT_OK) {
|
||||
try {
|
||||
ContentResolver cr = getContentResolver();
|
||||
Uri uri = data.getData();
|
||||
Cursor cursor = GeckoApp.mAppContext.getContentResolver().query(
|
||||
uri,
|
||||
new String[] { OpenableColumns.DISPLAY_NAME },
|
||||
null,
|
||||
null,
|
||||
null);
|
||||
String name = null;
|
||||
if (cursor != null) {
|
||||
try {
|
||||
if (cursor.moveToNext()) {
|
||||
name = cursor.getString(0);
|
||||
}
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
String fileName = "tmp_";
|
||||
String fileExt = null;
|
||||
int period;
|
||||
if (name == null || (period = name.lastIndexOf('.')) == -1) {
|
||||
String mimeType = cr.getType(uri);
|
||||
fileExt = "." + GeckoAppShell.getExtensionFromMimeType(mimeType);
|
||||
} else {
|
||||
fileExt = name.substring(period);
|
||||
fileName = name.substring(0, period);
|
||||
}
|
||||
File file = File.createTempFile(fileName, fileExt, sGREDir);
|
||||
|
||||
FileOutputStream fos = new FileOutputStream(file);
|
||||
InputStream is = cr.openInputStream(uri);
|
||||
byte[] buf = new byte[4096];
|
||||
int len = is.read(buf);
|
||||
while (len != -1) {
|
||||
fos.write(buf, 0, len);
|
||||
len = is.read(buf);
|
||||
}
|
||||
fos.close();
|
||||
filePickerResult = file.getAbsolutePath();
|
||||
}catch (Exception e) {
|
||||
Log.e(LOG_FILE_NAME, "showing file picker", e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
mFilePickerResult.put(filePickerResult);
|
||||
} catch (InterruptedException e) {
|
||||
Log.i(LOG_FILE_NAME, "error returning file picker result", e);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,150 +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.lang.Math;
|
||||
import java.util.Date;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import android.os.BatteryManager;
|
||||
|
||||
public class GeckoBatteryManager
|
||||
extends BroadcastReceiver
|
||||
{
|
||||
// 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 = -1.0;
|
||||
private final static double kUnknownRemainingTime = -1.0;
|
||||
|
||||
private static Date sLastLevelChange = new Date(0);
|
||||
private static boolean sNotificationsEnabled = false;
|
||||
private static double sLevel = kDefaultLevel;
|
||||
private static boolean sCharging = kDefaultCharging;
|
||||
private static double sRemainingTime = kDefaultRemainingTime;;
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (!intent.getAction().equals(Intent.ACTION_BATTERY_CHANGED)) {
|
||||
Log.e("GeckoBatteryManager", "Got an unexpected intent!");
|
||||
return;
|
||||
}
|
||||
|
||||
boolean previousCharging = isCharging();
|
||||
double previousLevel = getLevel();
|
||||
|
||||
if (intent.getBooleanExtra(BatteryManager.EXTRA_PRESENT, false)) {
|
||||
int plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
|
||||
if (plugged == -1) {
|
||||
sCharging = kDefaultCharging;
|
||||
Log.e("GeckoBatteryManager", "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 = new Date(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("GeckoBatteryManager", "Failed to get battery level!");
|
||||
sLevel = kDefaultLevel;
|
||||
} else {
|
||||
sLevel = current / max;
|
||||
}
|
||||
|
||||
if (sLevel == 1.0 && sCharging) {
|
||||
sRemainingTime = 0.0;
|
||||
} else if (sLevel != previousLevel) {
|
||||
// Estimate remaining time.
|
||||
if (sLastLevelChange.getTime() != 0) {
|
||||
Date currentTime = new Date();
|
||||
long dt = (currentTime.getTime() - sLastLevelChange.getTime()) / 1000;
|
||||
double dLevel = sLevel - previousLevel;
|
||||
|
||||
if (sCharging) {
|
||||
if (dLevel < 0) {
|
||||
Log.w("GeckoBatteryManager", "When charging, level should increase!");
|
||||
sRemainingTime = kUnknownRemainingTime;
|
||||
} else {
|
||||
sRemainingTime = Math.round(dt / dLevel * (1.0 - sLevel));
|
||||
}
|
||||
} else {
|
||||
if (dLevel > 0) {
|
||||
Log.w("GeckoBatteryManager", "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 = new Date();
|
||||
}
|
||||
}
|
||||
} 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() };
|
||||
}
|
||||
}
|
@ -1,30 +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.*;
|
||||
import android.net.*;
|
||||
|
||||
public class GeckoConnectivityReceiver
|
||||
extends BroadcastReceiver
|
||||
{
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String status;
|
||||
ConnectivityManager cm = (ConnectivityManager)
|
||||
context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
NetworkInfo info = cm.getActiveNetworkInfo();
|
||||
if (info == null)
|
||||
status = "unknown";
|
||||
else if (!info.isConnected())
|
||||
status = "down";
|
||||
else
|
||||
status = "up";
|
||||
|
||||
if (GeckoApp.checkLaunchState(GeckoApp.LaunchState.GeckoRunning))
|
||||
GeckoAppShell.onChangeNetworkLinkStatus(status);
|
||||
}
|
||||
}
|
@ -1,400 +0,0 @@
|
||||
/* -*- Mode: Java; 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.os.*;
|
||||
import android.app.*;
|
||||
import android.view.*;
|
||||
import android.content.*;
|
||||
import android.graphics.*;
|
||||
import android.widget.*;
|
||||
import android.hardware.*;
|
||||
import android.location.*;
|
||||
import android.util.FloatMath;
|
||||
import android.util.DisplayMetrics;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
public class GeckoEvent {
|
||||
// these constants should match the ones in mobile/android/base/GeckoEvent.java
|
||||
// as much as possible
|
||||
public static final int INVALID = -1;
|
||||
public static final int NATIVE_POKE = 0;
|
||||
public static final int KEY_EVENT = 1;
|
||||
public static final int MOTION_EVENT = 2;
|
||||
public static final int SENSOR_EVENT = 3;
|
||||
public static final int LOCATION_EVENT = 5;
|
||||
public static final int IME_EVENT = 6;
|
||||
public static final int DRAW = 7;
|
||||
public static final int SIZE_CHANGED = 8;
|
||||
public static final int ACTIVITY_STOPPING = 9;
|
||||
public static final int ACTIVITY_PAUSING = 10;
|
||||
public static final int ACTIVITY_SHUTDOWN = 11;
|
||||
public static final int LOAD_URI = 12;
|
||||
public static final int SURFACE_CREATED = 13;
|
||||
public static final int SURFACE_DESTROYED = 14;
|
||||
public static final int GECKO_EVENT_SYNC = 15;
|
||||
public static final int ACTIVITY_START = 17;
|
||||
public static final int SAVE_STATE = 18;
|
||||
public static final int BROADCAST = 19;
|
||||
public static final int VIEWPORT = 20;
|
||||
public static final int VISITED = 21;
|
||||
public static final int NETWORK_CHANGED = 22;
|
||||
public static final int SCREENORIENTATION_CHANGED = 27;
|
||||
|
||||
/**
|
||||
* These DOM_KEY_LOCATION constants mirror the DOM KeyboardEvent's constants.
|
||||
* @see https://developer.mozilla.org/en-US/docs/DOM/KeyboardEvent#Key_location_constants
|
||||
*/
|
||||
private static final int DOM_KEY_LOCATION_STANDARD = 0;
|
||||
private static final int DOM_KEY_LOCATION_LEFT = 1;
|
||||
private static final int DOM_KEY_LOCATION_RIGHT = 2;
|
||||
private static final int DOM_KEY_LOCATION_NUMPAD = 3;
|
||||
private static final int DOM_KEY_LOCATION_MOBILE = 4;
|
||||
private static final int DOM_KEY_LOCATION_JOYSTICK = 5;
|
||||
|
||||
public static final int IME_COMPOSITION_END = 0;
|
||||
public static final int IME_COMPOSITION_BEGIN = 1;
|
||||
public static final int IME_SET_TEXT = 2;
|
||||
public static final int IME_GET_TEXT = 3;
|
||||
public static final int IME_DELETE_TEXT = 4;
|
||||
public static final int IME_SET_SELECTION = 5;
|
||||
public static final int IME_GET_SELECTION = 6;
|
||||
public static final int IME_ADD_RANGE = 7;
|
||||
|
||||
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_UNDERLINE = 1;
|
||||
public static final int IME_RANGE_FORECOLOR = 2;
|
||||
public static final int IME_RANGE_BACKCOLOR = 4;
|
||||
|
||||
public int mType;
|
||||
public int mAction;
|
||||
public long mTime;
|
||||
public Point[] mPoints;
|
||||
public int[] mPointIndicies;
|
||||
public int mPointerIndex;
|
||||
public float[] mOrientations;
|
||||
public float[] mPressures;
|
||||
public Point[] mPointRadii;
|
||||
public Rect mRect;
|
||||
public double mX, mY, mZ;
|
||||
|
||||
public int mMetaState, mFlags;
|
||||
public int mKeyCode, mUnicodeChar;
|
||||
public int mRepeatCount;
|
||||
public int mOffset, mCount;
|
||||
public String mCharacters, mCharactersExtra;
|
||||
public int mRangeType, mRangeStyles;
|
||||
public int mRangeForeColor, mRangeBackColor;
|
||||
public Location mLocation;
|
||||
public Address mAddress;
|
||||
public int mDomKeyLocation;
|
||||
|
||||
public double mBandwidth;
|
||||
public boolean mCanBeMetered;
|
||||
|
||||
public short mScreenOrientation;
|
||||
|
||||
public int mNativeWindow;
|
||||
|
||||
public ByteBuffer mBuffer;
|
||||
|
||||
public GeckoEvent() {
|
||||
mType = NATIVE_POKE;
|
||||
}
|
||||
|
||||
public GeckoEvent(int evType) {
|
||||
mType = evType;
|
||||
}
|
||||
|
||||
public GeckoEvent(KeyEvent k) {
|
||||
mType = KEY_EVENT;
|
||||
mAction = k.getAction();
|
||||
mTime = k.getEventTime();
|
||||
mMetaState = k.getMetaState();
|
||||
mFlags = k.getFlags();
|
||||
mKeyCode = k.getKeyCode();
|
||||
mUnicodeChar = k.getUnicodeChar();
|
||||
mRepeatCount = k.getRepeatCount();
|
||||
mCharacters = k.getCharacters();
|
||||
mDomKeyLocation = isJoystickButton(mKeyCode) ? DOM_KEY_LOCATION_JOYSTICK : 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 GeckoEvent(MotionEvent m) {
|
||||
mType = MOTION_EVENT;
|
||||
mAction = m.getAction();
|
||||
mTime = m.getEventTime();
|
||||
mMetaState = m.getMetaState();
|
||||
|
||||
switch (mAction & MotionEvent.ACTION_MASK) {
|
||||
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: {
|
||||
mCount = m.getPointerCount();
|
||||
mPoints = new Point[mCount];
|
||||
mPointIndicies = new int[mCount];
|
||||
mOrientations = new float[mCount];
|
||||
mPressures = new float[mCount];
|
||||
mPointRadii = new Point[mCount];
|
||||
mPointerIndex = (mAction & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
|
||||
for (int i = 0; i < mCount; i++) {
|
||||
addMotionPoint(i, i, m);
|
||||
}
|
||||
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];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addMotionPoint(int index, int eventIndex, MotionEvent event) {
|
||||
PointF geckoPoint = new PointF(event.getX(eventIndex), event.getY(eventIndex));
|
||||
|
||||
mPoints[index] = new Point((int)Math.round(geckoPoint.x), (int)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);
|
||||
DisplayMetrics displaymetrics = new DisplayMetrics();
|
||||
GeckoApp.mAppContext.getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
|
||||
size = size*Math.min(displaymetrics.heightPixels, displaymetrics.widthPixels);
|
||||
mPointRadii[index] = new Point((int)size,(int)size);
|
||||
mOrientations[index] = 0;
|
||||
}
|
||||
mPressures[index] = event.getPressure(eventIndex);
|
||||
}
|
||||
|
||||
public GeckoEvent(SensorEvent s) {
|
||||
int sensor_type = s.sensor.getType();
|
||||
|
||||
switch(sensor_type) {
|
||||
case Sensor.TYPE_ACCELEROMETER:
|
||||
mType = SENSOR_EVENT;
|
||||
mFlags = 1; // hal::SENSOR_ACCELERATION
|
||||
mX = s.values[0];
|
||||
mY = s.values[1];
|
||||
mZ = s.values[2];
|
||||
break;
|
||||
|
||||
case Sensor.TYPE_ORIENTATION:
|
||||
mType = SENSOR_EVENT;
|
||||
mFlags = 0; // hal::SENSOR_ORIENTATION
|
||||
mX = s.values[0];
|
||||
mY = s.values[1];
|
||||
mZ = s.values[2];
|
||||
Log.i("GeckoEvent", "SensorEvent type = " + s.sensor.getType() + " " + s.sensor.getName() + " " + mX + " " + mY + " " + mZ );
|
||||
break;
|
||||
|
||||
case Sensor.TYPE_PROXIMITY:
|
||||
mType = SENSOR_EVENT;
|
||||
mFlags = 2; // hal:SENSOR_PROXIMITY
|
||||
mX = s.values[0];
|
||||
mY = 0;
|
||||
mZ = s.sensor.getMaximumRange();
|
||||
Log.i("GeckoEvent", "SensorEvent type = " + s.sensor.getType() +
|
||||
" " + s.sensor.getName() + " " + mX);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public GeckoEvent(Location l) {
|
||||
mType = LOCATION_EVENT;
|
||||
mLocation = l;
|
||||
}
|
||||
|
||||
public GeckoEvent(int imeAction, int offset, int count) {
|
||||
mType = IME_EVENT;
|
||||
mAction = imeAction;
|
||||
mOffset = offset;
|
||||
mCount = count;
|
||||
}
|
||||
|
||||
private void InitIMERange(int action, int offset, int count,
|
||||
int rangeType, int rangeStyles,
|
||||
int rangeForeColor, int rangeBackColor) {
|
||||
mType = IME_EVENT;
|
||||
mAction = action;
|
||||
mOffset = offset;
|
||||
mCount = count;
|
||||
mRangeType = rangeType;
|
||||
mRangeStyles = rangeStyles;
|
||||
mRangeForeColor = rangeForeColor;
|
||||
mRangeBackColor = rangeBackColor;
|
||||
return;
|
||||
}
|
||||
|
||||
public GeckoEvent(int offset, int count,
|
||||
int rangeType, int rangeStyles,
|
||||
int rangeForeColor, int rangeBackColor, String text) {
|
||||
InitIMERange(IME_SET_TEXT, offset, count, rangeType, rangeStyles,
|
||||
rangeForeColor, rangeBackColor);
|
||||
mCharacters = text;
|
||||
}
|
||||
|
||||
public GeckoEvent(int offset, int count,
|
||||
int rangeType, int rangeStyles,
|
||||
int rangeForeColor, int rangeBackColor) {
|
||||
InitIMERange(IME_ADD_RANGE, offset, count, rangeType, rangeStyles,
|
||||
rangeForeColor, rangeBackColor);
|
||||
}
|
||||
|
||||
public GeckoEvent(int etype, Rect dirty) {
|
||||
if (etype != DRAW) {
|
||||
mType = INVALID;
|
||||
return;
|
||||
}
|
||||
|
||||
mType = etype;
|
||||
mRect = dirty;
|
||||
}
|
||||
|
||||
public GeckoEvent(int etype, int w, int h, int screenw, int screenh) {
|
||||
if (etype != SIZE_CHANGED) {
|
||||
mType = INVALID;
|
||||
return;
|
||||
}
|
||||
|
||||
mType = etype;
|
||||
|
||||
mPoints = new Point[3];
|
||||
mPoints[0] = new Point(w, h);
|
||||
mPoints[1] = new Point(screenw, screenh);
|
||||
mPoints[2] = new Point(0, 0);
|
||||
}
|
||||
|
||||
public GeckoEvent(String subject, String data) {
|
||||
mType = BROADCAST;
|
||||
mCharacters = subject;
|
||||
mCharactersExtra = data;
|
||||
}
|
||||
|
||||
public GeckoEvent(String uri) {
|
||||
mType = LOAD_URI;
|
||||
mCharacters = uri;
|
||||
}
|
||||
|
||||
public GeckoEvent(double bandwidth, boolean canBeMetered) {
|
||||
mType = NETWORK_CHANGED;
|
||||
mBandwidth = bandwidth;
|
||||
mCanBeMetered = canBeMetered;
|
||||
}
|
||||
|
||||
public GeckoEvent(short aScreenOrientation) {
|
||||
mType = SCREENORIENTATION_CHANGED;
|
||||
mScreenOrientation = aScreenOrientation;
|
||||
}
|
||||
}
|
@ -1,701 +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 java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.*;
|
||||
|
||||
import android.os.*;
|
||||
import android.app.*;
|
||||
import android.text.*;
|
||||
import android.text.style.*;
|
||||
import android.view.*;
|
||||
import android.view.inputmethod.*;
|
||||
import android.content.*;
|
||||
import android.R;
|
||||
|
||||
import android.util.*;
|
||||
|
||||
public class GeckoInputConnection
|
||||
extends BaseInputConnection
|
||||
implements TextWatcher
|
||||
{
|
||||
private class ChangeNotification {
|
||||
public String mText;
|
||||
public int mStart;
|
||||
public int mEnd;
|
||||
public int mNewEnd;
|
||||
|
||||
ChangeNotification(String text, int start, int oldEnd, int newEnd) {
|
||||
mText = text;
|
||||
mStart = start;
|
||||
mEnd = oldEnd;
|
||||
mNewEnd = newEnd;
|
||||
}
|
||||
|
||||
ChangeNotification(int start, int end) {
|
||||
mText = null;
|
||||
mStart = start;
|
||||
mEnd = end;
|
||||
mNewEnd = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public GeckoInputConnection (View targetView) {
|
||||
super(targetView, true);
|
||||
mQueryResult = new SynchronousQueue<String>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean beginBatchEdit() {
|
||||
//Log.d("GeckoAppJava", "IME: beginBatchEdit");
|
||||
mBatchMode = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean commitCompletion(CompletionInfo text) {
|
||||
//Log.d("GeckoAppJava", "IME: commitCompletion");
|
||||
|
||||
return commitText(text.getText(), 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean commitText(CharSequence text, int newCursorPosition) {
|
||||
//Log.d("GeckoAppJava", "IME: commitText");
|
||||
|
||||
setComposingText(text, newCursorPosition);
|
||||
finishComposingText();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteSurroundingText(int leftLength, int rightLength) {
|
||||
//Log.d("GeckoAppJava", "IME: deleteSurroundingText");
|
||||
if (leftLength == 0 && rightLength == 0)
|
||||
return true;
|
||||
|
||||
/* deleteSurroundingText is supposed to ignore the composing text,
|
||||
so we cancel any pending composition, delete the text, and then
|
||||
restart the composition */
|
||||
|
||||
if (mComposing) {
|
||||
// Cancel current composition
|
||||
GeckoAppShell.sendEventToGecko(
|
||||
new GeckoEvent(0, 0, 0, 0, 0, 0, null));
|
||||
GeckoAppShell.sendEventToGecko(
|
||||
new GeckoEvent(GeckoEvent.IME_COMPOSITION_END, 0, 0));
|
||||
}
|
||||
|
||||
// Select text to be deleted
|
||||
int delStart, delLen;
|
||||
GeckoAppShell.sendEventToGecko(
|
||||
new GeckoEvent(GeckoEvent.IME_GET_SELECTION, 0, 0));
|
||||
try {
|
||||
mQueryResult.take();
|
||||
} catch (InterruptedException e) {
|
||||
Log.e("GeckoAppJava", "IME: deleteSurroundingText interrupted", e);
|
||||
return false;
|
||||
}
|
||||
delStart = mSelectionStart > leftLength ?
|
||||
mSelectionStart - leftLength : 0;
|
||||
delLen = mSelectionStart + rightLength - delStart;
|
||||
GeckoAppShell.sendEventToGecko(
|
||||
new GeckoEvent(GeckoEvent.IME_SET_SELECTION, delStart, delLen));
|
||||
|
||||
// Restore composition / delete text
|
||||
if (mComposing) {
|
||||
GeckoAppShell.sendEventToGecko(
|
||||
new GeckoEvent(GeckoEvent.IME_COMPOSITION_BEGIN, 0, 0));
|
||||
if (mComposingText.length() > 0) {
|
||||
/* IME_SET_TEXT doesn't work well with empty strings */
|
||||
GeckoAppShell.sendEventToGecko(
|
||||
new GeckoEvent(0, mComposingText.length(),
|
||||
GeckoEvent.IME_RANGE_RAWINPUT,
|
||||
GeckoEvent.IME_RANGE_UNDERLINE, 0, 0,
|
||||
mComposingText.toString()));
|
||||
}
|
||||
} else {
|
||||
GeckoAppShell.sendEventToGecko(
|
||||
new GeckoEvent(GeckoEvent.IME_DELETE_TEXT, 0, 0));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean endBatchEdit() {
|
||||
//Log.d("GeckoAppJava", "IME: endBatchEdit");
|
||||
|
||||
mBatchMode = false;
|
||||
|
||||
if (!mBatchChanges.isEmpty()) {
|
||||
InputMethodManager imm = (InputMethodManager)
|
||||
GeckoApp.surfaceView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
if (imm != null) {
|
||||
for (ChangeNotification n : mBatchChanges) {
|
||||
if (n.mText != null)
|
||||
notifyTextChange(imm, n.mText, n.mStart, n.mEnd, n.mNewEnd);
|
||||
else
|
||||
notifySelectionChange(imm, n.mStart, n.mEnd);
|
||||
}
|
||||
}
|
||||
mBatchChanges.clear();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean finishComposingText() {
|
||||
//Log.d("GeckoAppJava", "IME: finishComposingText");
|
||||
|
||||
if (mComposing) {
|
||||
// Set style to none
|
||||
GeckoAppShell.sendEventToGecko(
|
||||
new GeckoEvent(0, mComposingText.length(),
|
||||
GeckoEvent.IME_RANGE_RAWINPUT, 0, 0, 0,
|
||||
mComposingText));
|
||||
GeckoAppShell.sendEventToGecko(
|
||||
new GeckoEvent(GeckoEvent.IME_COMPOSITION_END, 0, 0));
|
||||
mComposing = false;
|
||||
mComposingText = "";
|
||||
|
||||
if (!mBatchMode) {
|
||||
// Make sure caret stays at the same position
|
||||
GeckoAppShell.sendEventToGecko(
|
||||
new GeckoEvent(GeckoEvent.IME_SET_SELECTION,
|
||||
mCompositionStart + mCompositionSelStart, 0));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCursorCapsMode(int reqModes) {
|
||||
//Log.d("GeckoAppJava", "IME: getCursorCapsMode");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Editable getEditable() {
|
||||
Log.w("GeckoAppJava", "IME: getEditable called from " +
|
||||
Thread.currentThread().getStackTrace()[0].toString());
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performContextMenuAction(int id) {
|
||||
//Log.d("GeckoAppJava", "IME: performContextMenuAction");
|
||||
|
||||
// First we need to ask Gecko to tell us the full contents of the
|
||||
// text field we're about to operate on.
|
||||
String text;
|
||||
GeckoAppShell.sendEventToGecko(
|
||||
new GeckoEvent(GeckoEvent.IME_GET_TEXT, 0, Integer.MAX_VALUE));
|
||||
try {
|
||||
text = mQueryResult.take();
|
||||
} catch (InterruptedException e) {
|
||||
Log.e("GeckoAppJava", "IME: performContextMenuAction interrupted", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (id) {
|
||||
case R.id.selectAll:
|
||||
setSelection(0, text.length());
|
||||
break;
|
||||
case R.id.cut:
|
||||
// Fill the clipboard
|
||||
GeckoAppShell.setClipboardText(text);
|
||||
// If GET_TEXT returned an empty selection, we'll select everything
|
||||
if (mSelectionLength <= 0)
|
||||
GeckoAppShell.sendEventToGecko(
|
||||
new GeckoEvent(GeckoEvent.IME_SET_SELECTION, 0, text.length()));
|
||||
GeckoAppShell.sendEventToGecko(
|
||||
new GeckoEvent(GeckoEvent.IME_DELETE_TEXT, 0, 0));
|
||||
break;
|
||||
case R.id.paste:
|
||||
commitText(GeckoAppShell.getClipboardText(), 1);
|
||||
break;
|
||||
case R.id.copy:
|
||||
// If there is no selection set, we must be doing "Copy All",
|
||||
// otherwise, we need to get the selection from Gecko
|
||||
if (mSelectionLength > 0) {
|
||||
GeckoAppShell.sendEventToGecko(
|
||||
new GeckoEvent(GeckoEvent.IME_GET_SELECTION, 0, 0));
|
||||
try {
|
||||
text = mQueryResult.take();
|
||||
} catch (InterruptedException e) {
|
||||
Log.e("GeckoAppJava", "IME: performContextMenuAction interrupted", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
GeckoAppShell.setClipboardText(text);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExtractedText getExtractedText(ExtractedTextRequest req, int flags) {
|
||||
if (req == null)
|
||||
return null;
|
||||
|
||||
// Bail out here if gecko isn't running, otherwise we deadlock
|
||||
// below when waiting for the reply to IME_GET_SELECTION.
|
||||
if (!GeckoApp.checkLaunchState(GeckoApp.LaunchState.GeckoRunning))
|
||||
return null;
|
||||
|
||||
//Log.d("GeckoAppJava", "IME: getExtractedText");
|
||||
|
||||
ExtractedText extract = new ExtractedText();
|
||||
extract.flags = 0;
|
||||
extract.partialStartOffset = -1;
|
||||
extract.partialEndOffset = -1;
|
||||
|
||||
GeckoAppShell.sendEventToGecko(
|
||||
new GeckoEvent(GeckoEvent.IME_GET_SELECTION, 0, 0));
|
||||
try {
|
||||
mQueryResult.take();
|
||||
} catch (InterruptedException e) {
|
||||
Log.e("GeckoAppJava", "IME: getExtractedText interrupted", e);
|
||||
return null;
|
||||
}
|
||||
extract.selectionStart = mSelectionStart;
|
||||
extract.selectionEnd = mSelectionStart + mSelectionLength;
|
||||
|
||||
// bug 617298 - IME_GET_TEXT sometimes gives the wrong result due to
|
||||
// a stale cache. Use a set of three workarounds:
|
||||
// 1. Sleep for 20 milliseconds and hope the child updates us with the new text.
|
||||
// Very evil and, consequentially, most effective.
|
||||
try {
|
||||
Thread.sleep(20);
|
||||
} catch (InterruptedException e) {}
|
||||
|
||||
GeckoAppShell.sendEventToGecko(
|
||||
new GeckoEvent(GeckoEvent.IME_GET_TEXT, 0, Integer.MAX_VALUE));
|
||||
try {
|
||||
extract.startOffset = 0;
|
||||
extract.text = mQueryResult.take();
|
||||
|
||||
// 2. Make a guess about what the text actually is
|
||||
if (mComposing && extract.selectionEnd > extract.text.length())
|
||||
extract.text = extract.text.subSequence(0, Math.min(extract.text.length(), mCompositionStart)) + mComposingText;
|
||||
|
||||
// 3. If all else fails, make sure our selection indexes make sense
|
||||
extract.selectionStart = Math.min(extract.selectionStart, extract.text.length());
|
||||
extract.selectionEnd = Math.min(extract.selectionEnd, extract.text.length());
|
||||
|
||||
if ((flags & GET_EXTRACTED_TEXT_MONITOR) != 0)
|
||||
mUpdateRequest = req;
|
||||
return extract;
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
Log.e("GeckoAppJava", "IME: getExtractedText interrupted", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getTextAfterCursor(int length, int flags) {
|
||||
//Log.d("GeckoAppJava", "IME: getTextAfterCursor");
|
||||
|
||||
GeckoAppShell.sendEventToGecko(
|
||||
new GeckoEvent(GeckoEvent.IME_GET_SELECTION, 0, 0));
|
||||
try {
|
||||
mQueryResult.take();
|
||||
} catch (InterruptedException e) {
|
||||
Log.e("GeckoAppJava", "IME: getTextBefore/AfterCursor interrupted", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
/* Compatible with both positive and negative length
|
||||
(no need for separate code for getTextBeforeCursor) */
|
||||
int textStart = mSelectionStart;
|
||||
int textLength = length;
|
||||
|
||||
if (length < 0) {
|
||||
textStart += length;
|
||||
textLength = -length;
|
||||
if (textStart < 0) {
|
||||
textStart = 0;
|
||||
textLength = mSelectionStart;
|
||||
}
|
||||
}
|
||||
|
||||
GeckoAppShell.sendEventToGecko(
|
||||
new GeckoEvent(GeckoEvent.IME_GET_TEXT, textStart, textLength));
|
||||
try {
|
||||
return mQueryResult.take();
|
||||
} catch (InterruptedException e) {
|
||||
Log.e("GeckoAppJava", "IME: getTextBefore/AfterCursor: Interrupted!", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getTextBeforeCursor(int length, int flags) {
|
||||
//Log.d("GeckoAppJava", "IME: getTextBeforeCursor");
|
||||
|
||||
return getTextAfterCursor(-length, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setComposingText(CharSequence text, int newCursorPosition) {
|
||||
//Log.d("GeckoAppJava", "IME: setComposingText");
|
||||
|
||||
// Set new composing text
|
||||
mComposingText = text != null ? text.toString() : "";
|
||||
|
||||
if (!mComposing) {
|
||||
if (mComposingText.length() == 0) {
|
||||
// Some IMEs such as iWnn sometimes call with empty composing
|
||||
// text. (See bug 664364)
|
||||
// If composing text is empty, ignore this and don't start
|
||||
// compositing.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get current selection
|
||||
GeckoAppShell.sendEventToGecko(
|
||||
new GeckoEvent(GeckoEvent.IME_GET_SELECTION, 0, 0));
|
||||
try {
|
||||
mQueryResult.take();
|
||||
} catch (InterruptedException e) {
|
||||
Log.e("GeckoAppJava", "IME: setComposingText interrupted", e);
|
||||
return false;
|
||||
}
|
||||
// Make sure we are in a composition
|
||||
GeckoAppShell.sendEventToGecko(
|
||||
new GeckoEvent(GeckoEvent.IME_COMPOSITION_BEGIN, 0, 0));
|
||||
mComposing = true;
|
||||
mCompositionStart = mSelectionLength >= 0 ?
|
||||
mSelectionStart : mSelectionStart + mSelectionLength;
|
||||
}
|
||||
|
||||
// Set new selection
|
||||
// New selection should be within the composition
|
||||
mCompositionSelStart = newCursorPosition > 0 ? mComposingText.length() : 0;
|
||||
mCompositionSelLen = 0;
|
||||
|
||||
// Handle composition text styles
|
||||
if (text != null && text instanceof Spanned) {
|
||||
Spanned span = (Spanned) text;
|
||||
int spanStart = 0, spanEnd = 0;
|
||||
boolean pastSelStart = false, pastSelEnd = false;
|
||||
|
||||
do {
|
||||
int rangeType = GeckoEvent.IME_RANGE_CONVERTEDTEXT;
|
||||
int rangeStyles = 0, rangeForeColor = 0, rangeBackColor = 0;
|
||||
|
||||
// Find next offset where there is a style transition
|
||||
spanEnd = span.nextSpanTransition(spanStart + 1, text.length(),
|
||||
CharacterStyle.class);
|
||||
|
||||
// We need to count the selection as a transition
|
||||
if (mCompositionSelLen >= 0) {
|
||||
if (!pastSelStart && spanEnd >= mCompositionSelStart) {
|
||||
spanEnd = mCompositionSelStart;
|
||||
pastSelStart = true;
|
||||
} else if (!pastSelEnd && spanEnd >=
|
||||
mCompositionSelStart + mCompositionSelLen) {
|
||||
spanEnd = mCompositionSelStart + mCompositionSelLen;
|
||||
pastSelEnd = true;
|
||||
rangeType = GeckoEvent.IME_RANGE_SELECTEDRAWTEXT;
|
||||
}
|
||||
} else {
|
||||
if (!pastSelEnd && spanEnd >=
|
||||
mCompositionSelStart + mCompositionSelLen) {
|
||||
spanEnd = mCompositionSelStart + mCompositionSelLen;
|
||||
pastSelEnd = true;
|
||||
} else if (!pastSelStart &&
|
||||
spanEnd >= mCompositionSelStart) {
|
||||
spanEnd = mCompositionSelStart;
|
||||
pastSelStart = true;
|
||||
rangeType = GeckoEvent.IME_RANGE_SELECTEDRAWTEXT;
|
||||
}
|
||||
}
|
||||
// Empty range, continue
|
||||
if (spanEnd <= spanStart)
|
||||
continue;
|
||||
|
||||
// Get and iterate through list of span objects within range
|
||||
CharacterStyle styles[] = span.getSpans(
|
||||
spanStart, spanEnd, CharacterStyle.class);
|
||||
|
||||
for (CharacterStyle style : styles) {
|
||||
if (style instanceof UnderlineSpan) {
|
||||
// Text should be underlined
|
||||
rangeStyles |= GeckoEvent.IME_RANGE_UNDERLINE;
|
||||
|
||||
} else if (style instanceof ForegroundColorSpan) {
|
||||
// Text should be of a different foreground color
|
||||
rangeStyles |= GeckoEvent.IME_RANGE_FORECOLOR;
|
||||
rangeForeColor =
|
||||
((ForegroundColorSpan)style).getForegroundColor();
|
||||
|
||||
} else if (style instanceof BackgroundColorSpan) {
|
||||
// Text should be of a different background color
|
||||
rangeStyles |= GeckoEvent.IME_RANGE_BACKCOLOR;
|
||||
rangeBackColor =
|
||||
((BackgroundColorSpan)style).getBackgroundColor();
|
||||
}
|
||||
}
|
||||
|
||||
// Add range to array, the actual styles are
|
||||
// applied when IME_SET_TEXT is sent
|
||||
GeckoAppShell.sendEventToGecko(
|
||||
new GeckoEvent(spanStart, spanEnd - spanStart,
|
||||
rangeType, rangeStyles,
|
||||
rangeForeColor, rangeBackColor));
|
||||
|
||||
spanStart = spanEnd;
|
||||
} while (spanStart < text.length());
|
||||
} else {
|
||||
GeckoAppShell.sendEventToGecko(
|
||||
new GeckoEvent(0, text == null ? 0 : text.length(),
|
||||
GeckoEvent.IME_RANGE_RAWINPUT,
|
||||
GeckoEvent.IME_RANGE_UNDERLINE, 0, 0));
|
||||
}
|
||||
|
||||
// Change composition (treating selection end as where the caret is)
|
||||
GeckoAppShell.sendEventToGecko(
|
||||
new GeckoEvent(mCompositionSelStart + mCompositionSelLen, 0,
|
||||
GeckoEvent.IME_RANGE_CARETPOSITION, 0, 0, 0,
|
||||
mComposingText));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setComposingRegion(int start, int end) {
|
||||
//Log.d("GeckoAppJava", "IME: setComposingRegion(start=" + start + ", end=" + end + ")");
|
||||
if (start < 0 || end < start)
|
||||
return true;
|
||||
|
||||
CharSequence text = null;
|
||||
if (start == mCompositionStart && end - start == mComposingText.length()) {
|
||||
// Use mComposingText to avoid extra call to Gecko
|
||||
text = mComposingText;
|
||||
}
|
||||
|
||||
finishComposingText();
|
||||
|
||||
if (text == null && start < end) {
|
||||
GeckoAppShell.sendEventToGecko(
|
||||
new GeckoEvent(GeckoEvent.IME_GET_TEXT, start, end - start));
|
||||
try {
|
||||
text = mQueryResult.take();
|
||||
} catch (InterruptedException e) {
|
||||
Log.e("GeckoAppJava", "IME: setComposingRegion interrupted", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
GeckoAppShell.sendEventToGecko(
|
||||
new GeckoEvent(GeckoEvent.IME_SET_SELECTION, start, end - start));
|
||||
|
||||
// Call setComposingText with the same text to start composition and let Gecko know about new composing region
|
||||
setComposingText(text, 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setSelection(int start, int end) {
|
||||
//Log.d("GeckoAppJava", "IME: setSelection");
|
||||
|
||||
if (mComposing) {
|
||||
/* Translate to fake selection positions */
|
||||
start -= mCompositionStart;
|
||||
end -= mCompositionStart;
|
||||
|
||||
if (start < 0)
|
||||
start = 0;
|
||||
else if (start > mComposingText.length())
|
||||
start = mComposingText.length();
|
||||
|
||||
if (end < 0)
|
||||
end = 0;
|
||||
else if (end > mComposingText.length())
|
||||
end = mComposingText.length();
|
||||
|
||||
mCompositionSelStart = start;
|
||||
mCompositionSelLen = end - start;
|
||||
} else {
|
||||
GeckoAppShell.sendEventToGecko(
|
||||
new GeckoEvent(GeckoEvent.IME_SET_SELECTION,
|
||||
start, end - start));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean onKeyDel() {
|
||||
// Some IMEs don't update us on deletions
|
||||
// In that case we are not updated when a composition
|
||||
// is destroyed, and Bad Things happen
|
||||
|
||||
if (!mComposing)
|
||||
return false;
|
||||
|
||||
if (mComposingText.length() > 0) {
|
||||
mComposingText = mComposingText.substring(0,
|
||||
mComposingText.length() - 1);
|
||||
if (mComposingText.length() > 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
commitText(null, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void notifyTextChange(InputMethodManager imm, String text,
|
||||
int start, int oldEnd, int newEnd) {
|
||||
// Log.d("GeckoAppShell", String.format("IME: notifyTextChange: text=%s s=%d ne=%d oe=%d",
|
||||
// text, start, newEnd, oldEnd));
|
||||
|
||||
if (mBatchMode) {
|
||||
mBatchChanges.add(new ChangeNotification(text, start, oldEnd, newEnd));
|
||||
return;
|
||||
}
|
||||
|
||||
mNumPendingChanges = Math.max(mNumPendingChanges - 1, 0);
|
||||
|
||||
// If there are pending changes, that means this text is not the most up-to-date version
|
||||
// and we'll step on ourselves if we change the editable right now.
|
||||
if (mNumPendingChanges == 0 && !text.contentEquals(GeckoApp.surfaceView.mEditable))
|
||||
GeckoApp.surfaceView.setEditable(text);
|
||||
|
||||
if (mUpdateRequest == null)
|
||||
return;
|
||||
|
||||
mUpdateExtract.flags = 0;
|
||||
|
||||
// We update from (0, oldEnd) to (0, newEnd) because some Android IMEs
|
||||
// assume that updates start at zero, according to jchen.
|
||||
mUpdateExtract.partialStartOffset = 0;
|
||||
mUpdateExtract.partialEndOffset = oldEnd;
|
||||
|
||||
// Faster to not query for selection
|
||||
mUpdateExtract.selectionStart = newEnd;
|
||||
mUpdateExtract.selectionEnd = newEnd;
|
||||
|
||||
mUpdateExtract.text = text.substring(0, newEnd);
|
||||
mUpdateExtract.startOffset = 0;
|
||||
|
||||
imm.updateExtractedText(GeckoApp.surfaceView,
|
||||
mUpdateRequest.token, mUpdateExtract);
|
||||
}
|
||||
|
||||
public void notifySelectionChange(InputMethodManager imm,
|
||||
int start, int end) {
|
||||
// Log.d("GeckoAppJava", String.format("IME: notifySelectionChange: s=%d e=%d", start, end));
|
||||
if (mBatchMode) {
|
||||
mBatchChanges.add(new ChangeNotification(start, end));
|
||||
return;
|
||||
}
|
||||
|
||||
if (mComposing)
|
||||
imm.updateSelection(GeckoApp.surfaceView,
|
||||
mCompositionStart + mCompositionSelStart,
|
||||
mCompositionStart + mCompositionSelStart + mCompositionSelLen,
|
||||
mCompositionStart,
|
||||
mCompositionStart + mComposingText.length());
|
||||
else
|
||||
imm.updateSelection(GeckoApp.surfaceView, start, end, -1, -1);
|
||||
|
||||
// We only change the selection if we are relatively sure that the text we have is
|
||||
// up-to-date. Bail out if we are stil expecting changes.
|
||||
if (mNumPendingChanges > 0)
|
||||
return;
|
||||
|
||||
int maxLen = GeckoApp.surfaceView.mEditable.length();
|
||||
Selection.setSelection(GeckoApp.surfaceView.mEditable,
|
||||
Math.min(start, maxLen),
|
||||
Math.min(end, maxLen));
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
mComposing = false;
|
||||
mComposingText = "";
|
||||
mUpdateRequest = null;
|
||||
mNumPendingChanges = 0;
|
||||
mBatchMode = false;
|
||||
mBatchChanges.clear();
|
||||
}
|
||||
|
||||
// TextWatcher
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count)
|
||||
{
|
||||
// Log.d("GeckoAppShell", String.format("IME: onTextChanged: t=%s s=%d b=%d l=%d",
|
||||
// s, start, before, count));
|
||||
|
||||
mNumPendingChanges++;
|
||||
GeckoAppShell.sendEventToGecko(
|
||||
new GeckoEvent(GeckoEvent.IME_SET_SELECTION, start, before));
|
||||
|
||||
if (count == 0) {
|
||||
GeckoAppShell.sendEventToGecko(
|
||||
new GeckoEvent(GeckoEvent.IME_DELETE_TEXT, 0, 0));
|
||||
} else {
|
||||
// Start and stop composition to force UI updates.
|
||||
finishComposingText();
|
||||
GeckoAppShell.sendEventToGecko(
|
||||
new GeckoEvent(GeckoEvent.IME_COMPOSITION_BEGIN, 0, 0));
|
||||
|
||||
GeckoAppShell.sendEventToGecko(
|
||||
new GeckoEvent(0, count,
|
||||
GeckoEvent.IME_RANGE_RAWINPUT, 0, 0, 0,
|
||||
s.subSequence(start, start + count).toString()));
|
||||
|
||||
GeckoAppShell.sendEventToGecko(
|
||||
new GeckoEvent(GeckoEvent.IME_COMPOSITION_END, 0, 0));
|
||||
|
||||
GeckoAppShell.sendEventToGecko(
|
||||
new GeckoEvent(GeckoEvent.IME_SET_SELECTION, start + count, 0));
|
||||
}
|
||||
|
||||
// Block this thread until all pending events are processed
|
||||
GeckoAppShell.geckoEventSync();
|
||||
}
|
||||
|
||||
public void afterTextChanged(Editable s)
|
||||
{
|
||||
}
|
||||
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after)
|
||||
{
|
||||
}
|
||||
|
||||
// Is a composition active?
|
||||
boolean mComposing;
|
||||
// Composition text when a composition is active
|
||||
String mComposingText = "";
|
||||
// Start index of the composition within the text body
|
||||
int mCompositionStart;
|
||||
/* During a composition, we should not alter the real selection,
|
||||
therefore we keep our own offsets to emulate selection */
|
||||
// Start of fake selection, relative to start of composition
|
||||
int mCompositionSelStart;
|
||||
// Length of fake selection
|
||||
int mCompositionSelLen;
|
||||
// Number of in flight changes
|
||||
int mNumPendingChanges;
|
||||
|
||||
boolean mBatchMode;
|
||||
private CopyOnWriteArrayList<ChangeNotification> mBatchChanges =
|
||||
new CopyOnWriteArrayList<ChangeNotification>();
|
||||
|
||||
ExtractedTextRequest mUpdateRequest;
|
||||
final ExtractedText mUpdateExtract = new ExtractedText();
|
||||
|
||||
int mSelectionStart, mSelectionLength;
|
||||
SynchronousQueue<String> mQueryResult;
|
||||
}
|
||||
|
@ -1,303 +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.lang.Math;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
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;
|
||||
|
||||
/*
|
||||
* 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
|
||||
{
|
||||
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 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() {
|
||||
mNetworkFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
|
||||
|
||||
mNetworkType = getNetworkType();
|
||||
}
|
||||
|
||||
public void start() {
|
||||
mShouldBeListening = true;
|
||||
updateNetworkType();
|
||||
|
||||
if (mShouldNotify) {
|
||||
startListening();
|
||||
}
|
||||
}
|
||||
|
||||
private void startListening() {
|
||||
GeckoApp.mAppContext.registerReceiver(sInstance, mNetworkFilter);
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
mShouldBeListening = false;
|
||||
|
||||
if (mShouldNotify) {
|
||||
stopListening();
|
||||
}
|
||||
}
|
||||
|
||||
private void stopListening() {
|
||||
GeckoApp.mAppContext.unregisterReceiver(sInstance);
|
||||
}
|
||||
|
||||
private void updateNetworkType() {
|
||||
NetworkType previousNetworkType = mNetworkType;
|
||||
mNetworkType = getNetworkType();
|
||||
|
||||
if (mNetworkType == previousNetworkType || !mShouldNotify) {
|
||||
return;
|
||||
}
|
||||
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(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)GeckoApp.mAppContext.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
|
||||
if (cm == null) {
|
||||
Log.w("GeckoNetworkManager", "Could not access Connectivity service");
|
||||
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("GeckoNetworkManager", "Ignoring the current network type.");
|
||||
return NetworkType.NETWORK_UNKNOWN;
|
||||
}
|
||||
|
||||
TelephonyManager tm =
|
||||
(TelephonyManager)GeckoApp.mAppContext.getSystemService(Context.TELEPHONY_SERVICE);
|
||||
|
||||
if (tm == null) {
|
||||
Log.w("GeckoNetworkManager", "Could not access Telephony service");
|
||||
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("GeckoNetworkManager", "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("GeckoNetworkManager", "Got an unexpected network type!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,161 +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.util.Log;
|
||||
import android.view.OrientationEventListener;
|
||||
import android.view.Surface;
|
||||
import android.content.pm.ActivityInfo;
|
||||
|
||||
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)
|
||||
|
||||
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;
|
||||
|
||||
private GeckoScreenOrientationListener() {
|
||||
mListener = new OrientationEventListenerImpl(GeckoApp.mAppContext);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
// NOTE: this is public so OrientationEventListenerImpl can access it.
|
||||
// Unfortunately, Java doesn't know about friendship.
|
||||
public void updateScreenOrientation() {
|
||||
int rotation = GeckoApp.mAppContext.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(new GeckoEvent(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 + ")");
|
||||
}
|
||||
|
||||
GeckoApp.mAppContext.setRequestedOrientation(orientation);
|
||||
updateScreenOrientation();
|
||||
}
|
||||
|
||||
public void unlockScreenOrientation() {
|
||||
GeckoApp.mAppContext.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
|
||||
updateScreenOrientation();
|
||||
}
|
||||
}
|
@ -1,777 +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 java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.locks.*;
|
||||
import java.util.concurrent.atomic.*;
|
||||
import java.util.zip.*;
|
||||
import java.nio.*;
|
||||
|
||||
import android.os.*;
|
||||
import android.app.*;
|
||||
import android.text.*;
|
||||
import android.text.method.*;
|
||||
import android.view.*;
|
||||
import android.view.inputmethod.*;
|
||||
import android.content.*;
|
||||
import android.graphics.*;
|
||||
import android.widget.*;
|
||||
import android.hardware.*;
|
||||
import android.location.*;
|
||||
import android.graphics.drawable.*;
|
||||
import android.content.res.*;
|
||||
|
||||
import android.util.*;
|
||||
|
||||
/*
|
||||
* GeckoSurfaceView implements a GL surface view,
|
||||
* similar to GLSurfaceView. However, since we
|
||||
* already have a thread for Gecko, we don't really want
|
||||
* a separate renderer thread that GLSurfaceView provides.
|
||||
*/
|
||||
class GeckoSurfaceView
|
||||
extends SurfaceView
|
||||
implements SurfaceHolder.Callback, SensorEventListener, LocationListener
|
||||
{
|
||||
private static final String LOG_FILE_NAME = "GeckoSurfaceView";
|
||||
|
||||
public GeckoSurfaceView(Context context) {
|
||||
super(context);
|
||||
|
||||
getHolder().addCallback(this);
|
||||
inputConnection = new GeckoInputConnection(this);
|
||||
setFocusable(true);
|
||||
setFocusableInTouchMode(true);
|
||||
|
||||
DisplayMetrics metrics = new DisplayMetrics();
|
||||
GeckoApp.mAppContext.getWindowManager().
|
||||
getDefaultDisplay().getMetrics(metrics);
|
||||
mWidth = metrics.widthPixels;
|
||||
mHeight = metrics.heightPixels;
|
||||
mBufferWidth = 0;
|
||||
mBufferHeight = 0;
|
||||
|
||||
mSurfaceLock = new ReentrantLock();
|
||||
|
||||
mEditableFactory = Editable.Factory.getInstance();
|
||||
initEditable("");
|
||||
mIMEState = IME_STATE_DISABLED;
|
||||
mIMETypeHint = "";
|
||||
mIMEModeHint = "";
|
||||
mIMEActionHint = "";
|
||||
}
|
||||
|
||||
protected void finalize() throws Throwable {
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
void drawSplashScreen() {
|
||||
this.drawSplashScreen(getHolder(), mWidth, mHeight);
|
||||
}
|
||||
|
||||
void drawSplashScreen(SurfaceHolder holder, int width, int height) {
|
||||
// No splash screen for Honeycomb or greater
|
||||
if (Build.VERSION.SDK_INT >= 11) {
|
||||
Log.i(LOG_FILE_NAME, "skipping splash screen");
|
||||
return;
|
||||
}
|
||||
|
||||
Canvas c = holder.lockCanvas();
|
||||
if (c == null) {
|
||||
Log.i(LOG_FILE_NAME, "canvas is null");
|
||||
return;
|
||||
}
|
||||
|
||||
Resources res = getResources();
|
||||
|
||||
File watchDir = new File(GeckoApp.sGREDir, "components");
|
||||
if (watchDir.exists() == false) {
|
||||
// Just show the simple splash screen for "new profile" startup
|
||||
c.drawColor(res.getColor(R.color.splash_background));
|
||||
Drawable drawable = res.getDrawable(R.drawable.splash);
|
||||
int w = drawable.getIntrinsicWidth();
|
||||
int h = drawable.getIntrinsicHeight();
|
||||
int x = (width - w) / 2;
|
||||
int y = (height - h) / 2 - 16;
|
||||
drawable.setBounds(x, y, x + w, y + h);
|
||||
drawable.draw(c);
|
||||
|
||||
Paint p = new Paint();
|
||||
p.setTextAlign(Paint.Align.CENTER);
|
||||
p.setTextSize(32f);
|
||||
p.setAntiAlias(true);
|
||||
p.setColor(res.getColor(R.color.splash_msgfont));
|
||||
c.drawText(res.getString(R.string.splash_firstrun), width / 2, y + h + 16, p);
|
||||
} else {
|
||||
// Show the static UI for normal startup
|
||||
DisplayMetrics metrics = new DisplayMetrics();
|
||||
GeckoApp.mAppContext.getWindowManager().getDefaultDisplay().getMetrics(metrics);
|
||||
|
||||
// Default to DENSITY_HIGH sizes
|
||||
int toolbarHeight = 80;
|
||||
int faviconOffset = 25;
|
||||
float urlHeight = 24f;
|
||||
int urlOffsetX = 80;
|
||||
int urlOffsetY = 48;
|
||||
if (metrics.densityDpi == DisplayMetrics.DENSITY_MEDIUM) {
|
||||
toolbarHeight = 53;
|
||||
faviconOffset = 10;
|
||||
urlHeight = 16f;
|
||||
urlOffsetX = 53;
|
||||
urlOffsetY = 32;
|
||||
}
|
||||
|
||||
c.drawColor(res.getColor(R.color.splash_content));
|
||||
Drawable toolbar = res.getDrawable(Build.VERSION.SDK_INT > 8 ?
|
||||
R.drawable.splash_v9 :
|
||||
R.drawable.splash_v8);
|
||||
toolbar.setBounds(0, 0, width, toolbarHeight);
|
||||
toolbar.draw(c);
|
||||
|
||||
// XUL/CSS always uses 32px width and height for favicon
|
||||
Drawable favicon = res.getDrawable(R.drawable.favicon32);
|
||||
favicon.setBounds(faviconOffset, faviconOffset, 32 + faviconOffset, 32 + faviconOffset);
|
||||
favicon.draw(c);
|
||||
|
||||
if (GeckoSurfaceView.mSplashURL != "") {
|
||||
TextPaint p = new TextPaint();
|
||||
p.setTextAlign(Paint.Align.LEFT);
|
||||
p.setTextSize(urlHeight);
|
||||
p.setAntiAlias(true);
|
||||
p.setColor(res.getColor(R.color.splash_urlfont));
|
||||
String url = TextUtils.ellipsize(GeckoSurfaceView.mSplashURL, p, width - urlOffsetX * 2, TextUtils.TruncateAt.END).toString();
|
||||
c.drawText(url, urlOffsetX, urlOffsetY, p);
|
||||
}
|
||||
}
|
||||
holder.unlockCanvasAndPost(c);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called on main thread
|
||||
*/
|
||||
|
||||
public void draw(SurfaceHolder holder, ByteBuffer buffer) {
|
||||
if (buffer == null || buffer.capacity() != (mWidth * mHeight * 2))
|
||||
return;
|
||||
|
||||
synchronized (mSoftwareBuffer) {
|
||||
if (buffer != mSoftwareBuffer || mSoftwareBufferCopy == null)
|
||||
return;
|
||||
|
||||
Canvas c = holder.lockCanvas();
|
||||
if (c == null)
|
||||
return;
|
||||
mSoftwareBufferCopy.copyPixelsFromBuffer(buffer);
|
||||
c.drawBitmap(mSoftwareBufferCopy, 0, 0, null);
|
||||
holder.unlockCanvasAndPost(c);
|
||||
}
|
||||
}
|
||||
|
||||
public void draw(SurfaceHolder holder, Bitmap bitmap) {
|
||||
if (bitmap == null ||
|
||||
bitmap.getWidth() != mWidth || bitmap.getHeight() != mHeight)
|
||||
return;
|
||||
|
||||
synchronized (mSoftwareBitmap) {
|
||||
if (bitmap != mSoftwareBitmap)
|
||||
return;
|
||||
|
||||
Canvas c = holder.lockCanvas();
|
||||
if (c == null)
|
||||
return;
|
||||
c.drawBitmap(bitmap, 0, 0, null);
|
||||
holder.unlockCanvasAndPost(c);
|
||||
}
|
||||
}
|
||||
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
||||
|
||||
// On pre-Honeycomb, force exactly one frame of the previous size
|
||||
// to render because the surface change is only seen by GLES after we
|
||||
// have swapped the back buffer (i.e. the buffer size only changes
|
||||
// after the next swap buffer). We need to make sure Gecko's view
|
||||
// resizes when Android's buffer resizes.
|
||||
// In Honeycomb, the buffer size changes immediately, so rendering a
|
||||
// frame of the previous size is unnecessary (and wrong).
|
||||
if (mDrawMode == DRAW_GLES_2 &&
|
||||
(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB)) {
|
||||
// When we get a surfaceChange event, we have 0 to n paint events
|
||||
// waiting in the Gecko event queue. We will make the first
|
||||
// succeed and the abort the others.
|
||||
mDrawSingleFrame = true;
|
||||
if (!mInDrawing) {
|
||||
// Queue at least one paint event in case none are queued.
|
||||
GeckoAppShell.scheduleRedraw();
|
||||
}
|
||||
GeckoAppShell.geckoEventSync();
|
||||
mDrawSingleFrame = false;
|
||||
mAbortDraw = false;
|
||||
}
|
||||
|
||||
if (mShowingSplashScreen)
|
||||
drawSplashScreen(holder, width, height);
|
||||
|
||||
mSurfaceLock.lock();
|
||||
|
||||
if (mInDrawing) {
|
||||
Log.w(LOG_FILE_NAME, "surfaceChanged while mInDrawing is true!");
|
||||
}
|
||||
|
||||
boolean invalidSize;
|
||||
|
||||
if (width == 0 || height == 0) {
|
||||
mSoftwareBitmap = null;
|
||||
mSoftwareBuffer = null;
|
||||
mSoftwareBufferCopy = null;
|
||||
invalidSize = true;
|
||||
} else {
|
||||
invalidSize = false;
|
||||
}
|
||||
|
||||
boolean doSyncDraw =
|
||||
mDrawMode == DRAW_2D &&
|
||||
!invalidSize &&
|
||||
GeckoApp.checkLaunchState(GeckoApp.LaunchState.GeckoRunning);
|
||||
mSyncDraw = doSyncDraw;
|
||||
|
||||
mFormat = format;
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
mSurfaceValid = true;
|
||||
|
||||
Log.i(LOG_FILE_NAME, "surfaceChanged: fmt: " + format + " dim: " + width + " " + height);
|
||||
|
||||
try {
|
||||
DisplayMetrics metrics = new DisplayMetrics();
|
||||
GeckoApp.mAppContext.getWindowManager().getDefaultDisplay().getMetrics(metrics);
|
||||
|
||||
GeckoEvent e = new GeckoEvent(GeckoEvent.SIZE_CHANGED, width, height,
|
||||
metrics.widthPixels, metrics.heightPixels);
|
||||
GeckoAppShell.sendEventToGecko(e);
|
||||
} finally {
|
||||
mSurfaceLock.unlock();
|
||||
}
|
||||
|
||||
if (doSyncDraw) {
|
||||
GeckoAppShell.scheduleRedraw();
|
||||
|
||||
Object syncDrawObject = null;
|
||||
try {
|
||||
syncDrawObject = mSyncDraws.take();
|
||||
} catch (InterruptedException ie) {
|
||||
Log.e(LOG_FILE_NAME, "Threw exception while getting sync draw bitmap/buffer: ", ie);
|
||||
}
|
||||
if (syncDrawObject != null) {
|
||||
if (syncDrawObject instanceof Bitmap)
|
||||
draw(holder, (Bitmap)syncDrawObject);
|
||||
else
|
||||
draw(holder, (ByteBuffer)syncDrawObject);
|
||||
} else {
|
||||
Log.e("GeckoSurfaceViewJava", "Synchronised draw object is null");
|
||||
}
|
||||
} else if (!mShowingSplashScreen) {
|
||||
// Make sure a frame is drawn before we return
|
||||
// otherwise we see artifacts or a black screen
|
||||
GeckoAppShell.scheduleRedraw();
|
||||
GeckoAppShell.geckoEventSync();
|
||||
}
|
||||
}
|
||||
|
||||
public void surfaceCreated(SurfaceHolder holder) {
|
||||
Log.i(LOG_FILE_NAME, "surface created");
|
||||
GeckoEvent e = new GeckoEvent(GeckoEvent.SURFACE_CREATED);
|
||||
GeckoAppShell.sendEventToGecko(e);
|
||||
if (mShowingSplashScreen)
|
||||
drawSplashScreen();
|
||||
}
|
||||
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
Log.i(LOG_FILE_NAME, "surface destroyed");
|
||||
mSurfaceValid = false;
|
||||
mSoftwareBuffer = null;
|
||||
mSoftwareBufferCopy = null;
|
||||
mSoftwareBitmap = null;
|
||||
GeckoEvent e = new GeckoEvent(GeckoEvent.SURFACE_DESTROYED);
|
||||
if (mDrawMode == DRAW_GLES_2) {
|
||||
// Ensure GL cleanup occurs before we return.
|
||||
GeckoAppShell.sendEventToGeckoSync(e);
|
||||
} else {
|
||||
GeckoAppShell.sendEventToGecko(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Bitmap getSoftwareDrawBitmap() {
|
||||
if (mSoftwareBitmap == null ||
|
||||
mSoftwareBitmap.getHeight() != mHeight ||
|
||||
mSoftwareBitmap.getWidth() != mWidth) {
|
||||
mSoftwareBitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.RGB_565);
|
||||
}
|
||||
|
||||
mDrawMode = DRAW_2D;
|
||||
return mSoftwareBitmap;
|
||||
}
|
||||
|
||||
public ByteBuffer getSoftwareDrawBuffer() {
|
||||
// We store pixels in 565 format, so two bytes per pixel (explaining
|
||||
// the * 2 in the following check/allocation)
|
||||
if (mSoftwareBuffer == null ||
|
||||
mSoftwareBuffer.capacity() != (mWidth * mHeight * 2)) {
|
||||
mSoftwareBuffer = ByteBuffer.allocateDirect(mWidth * mHeight * 2);
|
||||
}
|
||||
|
||||
if (mSoftwareBufferCopy == null ||
|
||||
mSoftwareBufferCopy.getHeight() != mHeight ||
|
||||
mSoftwareBufferCopy.getWidth() != mWidth) {
|
||||
mSoftwareBufferCopy = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.RGB_565);
|
||||
}
|
||||
|
||||
mDrawMode = DRAW_2D;
|
||||
return mSoftwareBuffer;
|
||||
}
|
||||
|
||||
public Surface getSurface() {
|
||||
return getHolder().getSurface();
|
||||
}
|
||||
|
||||
/*
|
||||
* Called on Gecko thread
|
||||
*/
|
||||
|
||||
public static final int DRAW_ERROR = 0;
|
||||
public static final int DRAW_GLES_2 = 1;
|
||||
public static final int DRAW_2D = 2;
|
||||
// Drawing is disable when the surface buffer
|
||||
// has changed size but we haven't yet processed the
|
||||
// resize event.
|
||||
public static final int DRAW_DISABLED = 3;
|
||||
|
||||
public int beginDrawing() {
|
||||
if (mInDrawing) {
|
||||
Log.e(LOG_FILE_NAME, "Recursive beginDrawing call!");
|
||||
return DRAW_ERROR;
|
||||
}
|
||||
|
||||
// Once we drawn our first frame after resize we can ignore
|
||||
// the other draw events until we handle the resize events.
|
||||
if (mAbortDraw) {
|
||||
return DRAW_DISABLED;
|
||||
}
|
||||
|
||||
/* Grab the lock, which we'll hold while we're drawing.
|
||||
* It gets released in endDrawing(), and is also used in surfaceChanged
|
||||
* to make sure that we don't change our surface details while
|
||||
* we're in the middle of drawing (and especially in the middle of
|
||||
* executing beginDrawing/endDrawing).
|
||||
*
|
||||
* We might not need to hold this lock in between
|
||||
* beginDrawing/endDrawing, and might just be able to make
|
||||
* surfaceChanged, beginDrawing, and endDrawing synchronized,
|
||||
* but this way is safer for now.
|
||||
*/
|
||||
mSurfaceLock.lock();
|
||||
|
||||
if (!mSurfaceValid) {
|
||||
Log.e(LOG_FILE_NAME, "Surface not valid");
|
||||
mSurfaceLock.unlock();
|
||||
return DRAW_ERROR;
|
||||
}
|
||||
|
||||
mInDrawing = true;
|
||||
mDrawMode = DRAW_GLES_2;
|
||||
return DRAW_GLES_2;
|
||||
}
|
||||
|
||||
public void endDrawing() {
|
||||
if (!mInDrawing) {
|
||||
Log.e(LOG_FILE_NAME, "endDrawing without beginDrawing!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mDrawSingleFrame)
|
||||
mAbortDraw = true;
|
||||
|
||||
try {
|
||||
if (!mSurfaceValid) {
|
||||
Log.e(LOG_FILE_NAME, "endDrawing with false mSurfaceValid");
|
||||
return;
|
||||
}
|
||||
} finally {
|
||||
mInDrawing = false;
|
||||
|
||||
if (!mSurfaceLock.isHeldByCurrentThread())
|
||||
Log.e(LOG_FILE_NAME, "endDrawing while mSurfaceLock not held by current thread!");
|
||||
|
||||
mSurfaceLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/* How this works:
|
||||
* Whenever we want to draw, we want to be sure that we do not lock
|
||||
* the canvas unless we're sure we can draw. Locking the canvas clears
|
||||
* the canvas to black in most cases, causing a black flash.
|
||||
* At the same time, the surface can resize/disappear at any moment
|
||||
* unless the canvas is locked.
|
||||
* Draws originate from a different thread so the surface could change
|
||||
* at any moment while we try to draw until we lock the canvas.
|
||||
*
|
||||
* Also, never try to lock the canvas while holding the surface lock
|
||||
* unless you're in SurfaceChanged, in which case the canvas was already
|
||||
* locked. Surface lock -> Canvas lock will lead to AB-BA deadlocks.
|
||||
*/
|
||||
public void draw2D(Bitmap bitmap, int width, int height) {
|
||||
// mSurfaceLock ensures that we get mSyncDraw/mSoftwareBitmap/etc.
|
||||
// set correctly before determining whether we should do a sync draw
|
||||
mSurfaceLock.lock();
|
||||
try {
|
||||
if (mSyncDraw) {
|
||||
if (bitmap != mSoftwareBitmap || width != mWidth || height != mHeight)
|
||||
return;
|
||||
mSyncDraw = false;
|
||||
try {
|
||||
mSyncDraws.put(bitmap);
|
||||
} catch (InterruptedException ie) {
|
||||
Log.e(LOG_FILE_NAME, "Threw exception while getting sync draws queue: ", ie);
|
||||
}
|
||||
return;
|
||||
}
|
||||
} finally {
|
||||
mSurfaceLock.unlock();
|
||||
}
|
||||
|
||||
draw(getHolder(), bitmap);
|
||||
}
|
||||
|
||||
public void draw2D(ByteBuffer buffer, int stride) {
|
||||
mSurfaceLock.lock();
|
||||
try {
|
||||
if (mSyncDraw) {
|
||||
if (buffer != mSoftwareBuffer || stride != (mWidth * 2))
|
||||
return;
|
||||
mSyncDraw = false;
|
||||
try {
|
||||
mSyncDraws.put(buffer);
|
||||
} catch (InterruptedException ie) {
|
||||
Log.e(LOG_FILE_NAME, "Threw exception while getting sync bitmaps queue: ", ie);
|
||||
}
|
||||
return;
|
||||
}
|
||||
} finally {
|
||||
mSurfaceLock.unlock();
|
||||
}
|
||||
|
||||
draw(getHolder(), buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCheckIsTextEditor () {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
|
||||
outAttrs.inputType = InputType.TYPE_CLASS_TEXT;
|
||||
outAttrs.imeOptions = EditorInfo.IME_ACTION_NONE;
|
||||
outAttrs.actionLabel = null;
|
||||
mKeyListener = TextKeyListener.getInstance();
|
||||
|
||||
if (mIMEState == IME_STATE_PASSWORD)
|
||||
outAttrs.inputType |= InputType.TYPE_TEXT_VARIATION_PASSWORD;
|
||||
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;
|
||||
else if (mIMETypeHint.equalsIgnoreCase("datetime") ||
|
||||
mIMETypeHint.equalsIgnoreCase("datetime-local"))
|
||||
outAttrs.inputType = InputType.TYPE_CLASS_DATETIME |
|
||||
InputType.TYPE_DATETIME_VARIATION_NORMAL;
|
||||
else if (mIMETypeHint.equalsIgnoreCase("date"))
|
||||
outAttrs.inputType = InputType.TYPE_CLASS_DATETIME |
|
||||
InputType.TYPE_DATETIME_VARIATION_DATE;
|
||||
else if (mIMETypeHint.equalsIgnoreCase("time"))
|
||||
outAttrs.inputType = InputType.TYPE_CLASS_DATETIME |
|
||||
InputType.TYPE_DATETIME_VARIATION_TIME;
|
||||
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 if (mIMEModeHint.equalsIgnoreCase("uppercase"))
|
||||
outAttrs.inputType |= InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS;
|
||||
else if (mIMEModeHint.equalsIgnoreCase("lowercase"))
|
||||
outAttrs.inputType = InputType.TYPE_CLASS_TEXT;
|
||||
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;
|
||||
|
||||
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 != null && mIMEActionHint.length() != 0)
|
||||
outAttrs.actionLabel = mIMEActionHint;
|
||||
|
||||
if (mIMELandscapeFS == false)
|
||||
outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_EXTRACT_UI;
|
||||
|
||||
inputConnection.reset();
|
||||
return inputConnection;
|
||||
}
|
||||
|
||||
public void setEditable(String contents)
|
||||
{
|
||||
mEditable.removeSpan(inputConnection);
|
||||
mEditable.replace(0, mEditable.length(), contents);
|
||||
mEditable.setSpan(inputConnection, 0, contents.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
|
||||
Selection.setSelection(mEditable, contents.length());
|
||||
}
|
||||
|
||||
public void initEditable(String contents)
|
||||
{
|
||||
mEditable = mEditableFactory.newEditable(contents);
|
||||
mEditable.setSpan(inputConnection, 0, contents.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
|
||||
Selection.setSelection(mEditable, contents.length());
|
||||
}
|
||||
|
||||
// accelerometer
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy)
|
||||
{
|
||||
}
|
||||
|
||||
public void onSensorChanged(SensorEvent event)
|
||||
{
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
|
||||
}
|
||||
|
||||
// geolocation
|
||||
public void onLocationChanged(Location location)
|
||||
{
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(location));
|
||||
}
|
||||
|
||||
public void onProviderDisabled(String provider)
|
||||
{
|
||||
}
|
||||
|
||||
public void onProviderEnabled(String provider)
|
||||
{
|
||||
}
|
||||
|
||||
public void onStatusChanged(String provider, int status, Bundle extras)
|
||||
{
|
||||
}
|
||||
|
||||
// event stuff
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
|
||||
if (event.isSystem())
|
||||
return super.onKeyPreIme(keyCode, event);
|
||||
|
||||
switch (event.getAction()) {
|
||||
case KeyEvent.ACTION_DOWN:
|
||||
return processKeyDown(keyCode, event, true);
|
||||
case KeyEvent.ACTION_UP:
|
||||
return processKeyUp(keyCode, event, true);
|
||||
case KeyEvent.ACTION_MULTIPLE:
|
||||
return onKeyMultiple(keyCode, event.getRepeatCount(), event);
|
||||
}
|
||||
return super.onKeyPreIme(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
return processKeyDown(keyCode, event, false);
|
||||
}
|
||||
|
||||
private boolean processKeyDown(int keyCode, KeyEvent event, boolean isPreIme) {
|
||||
switch (keyCode) {
|
||||
case KeyEvent.KEYCODE_BACK:
|
||||
if (event.getRepeatCount() == 0) {
|
||||
event.startTracking();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
case KeyEvent.KEYCODE_MENU:
|
||||
if (event.getRepeatCount() == 0) {
|
||||
event.startTracking();
|
||||
break;
|
||||
} else if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
|
||||
break;
|
||||
}
|
||||
// Ignore repeats for KEYCODE_MENU; they confuse the widget code.
|
||||
return false;
|
||||
case KeyEvent.KEYCODE_VOLUME_UP:
|
||||
case KeyEvent.KEYCODE_VOLUME_DOWN:
|
||||
case KeyEvent.KEYCODE_SEARCH:
|
||||
return false;
|
||||
case KeyEvent.KEYCODE_DEL:
|
||||
// See comments in GeckoInputConnection.onKeyDel
|
||||
if (inputConnection != null &&
|
||||
inputConnection.onKeyDel()) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case KeyEvent.KEYCODE_ENTER:
|
||||
if ((event.getFlags() & KeyEvent.FLAG_EDITOR_ACTION) != 0 &&
|
||||
mIMEActionHint.equalsIgnoreCase("next"))
|
||||
event = new KeyEvent(event.getAction(), KeyEvent.KEYCODE_TAB);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (isPreIme && mIMEState != IME_STATE_DISABLED &&
|
||||
(event.getMetaState() & KeyEvent.META_ALT_ON) == 0)
|
||||
// Let active IME process pre-IME key events
|
||||
return false;
|
||||
|
||||
// KeyListener returns true if it handled the event for us.
|
||||
if (mIMEState == IME_STATE_DISABLED ||
|
||||
keyCode == KeyEvent.KEYCODE_ENTER ||
|
||||
keyCode == KeyEvent.KEYCODE_DEL ||
|
||||
(event.getFlags() & KeyEvent.FLAG_SOFT_KEYBOARD) != 0 ||
|
||||
!mKeyListener.onKeyDown(this, mEditable, keyCode, event))
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyUp(int keyCode, KeyEvent event) {
|
||||
return processKeyUp(keyCode, event, false);
|
||||
}
|
||||
|
||||
private boolean processKeyUp(int keyCode, KeyEvent event, boolean isPreIme) {
|
||||
switch (keyCode) {
|
||||
case KeyEvent.KEYCODE_BACK:
|
||||
if (!event.isTracking() || event.isCanceled())
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (isPreIme && mIMEState != IME_STATE_DISABLED &&
|
||||
(event.getMetaState() & KeyEvent.META_ALT_ON) == 0)
|
||||
// Let active IME process pre-IME key events
|
||||
return false;
|
||||
|
||||
if (mIMEState == IME_STATE_DISABLED ||
|
||||
keyCode == KeyEvent.KEYCODE_ENTER ||
|
||||
keyCode == KeyEvent.KEYCODE_DEL ||
|
||||
(event.getFlags() & KeyEvent.FLAG_SOFT_KEYBOARD) != 0 ||
|
||||
!mKeyListener.onKeyUp(this, mEditable, keyCode, event))
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
|
||||
switch (keyCode) {
|
||||
case KeyEvent.KEYCODE_BACK:
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
|
||||
return true;
|
||||
case KeyEvent.KEYCODE_MENU:
|
||||
InputMethodManager imm = (InputMethodManager)
|
||||
getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
imm.toggleSoftInputFromWindow(getWindowToken(),
|
||||
imm.SHOW_FORCED, 0);
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Is this surface valid for drawing into?
|
||||
boolean mSurfaceValid;
|
||||
|
||||
// Are we actively between beginDrawing/endDrawing?
|
||||
boolean mInDrawing;
|
||||
|
||||
// Used to finish the current buffer before changing the surface size
|
||||
boolean mDrawSingleFrame = false;
|
||||
boolean mAbortDraw = false;
|
||||
|
||||
// Are we waiting for a buffer to draw in surfaceChanged?
|
||||
boolean mSyncDraw;
|
||||
|
||||
// True if gecko requests a buffer
|
||||
int mDrawMode;
|
||||
|
||||
static boolean mShowingSplashScreen = true;
|
||||
static String mSplashURL = "";
|
||||
|
||||
// let's not change stuff around while we're in the middle of
|
||||
// starting drawing, ending drawing, or changing surface
|
||||
// characteristics
|
||||
ReentrantLock mSurfaceLock;
|
||||
|
||||
// Surface format, from surfaceChanged. Largely
|
||||
// useless.
|
||||
int mFormat;
|
||||
|
||||
// the dimensions of the surface
|
||||
int mWidth;
|
||||
int mHeight;
|
||||
|
||||
// the dimensions of the buffer we're using for drawing,
|
||||
// that is the software buffer or the EGLSurface
|
||||
int mBufferWidth;
|
||||
int mBufferHeight;
|
||||
|
||||
// IME stuff
|
||||
public static final int IME_STATE_DISABLED = 0;
|
||||
public static final int IME_STATE_ENABLED = 1;
|
||||
public static final int IME_STATE_PASSWORD = 2;
|
||||
public static final int IME_STATE_PLUGIN = 3;
|
||||
|
||||
GeckoInputConnection inputConnection;
|
||||
KeyListener mKeyListener;
|
||||
Editable mEditable;
|
||||
Editable.Factory mEditableFactory;
|
||||
int mIMEState;
|
||||
String mIMETypeHint;
|
||||
String mIMEModeHint;
|
||||
String mIMEActionHint;
|
||||
boolean mIMELandscapeFS;
|
||||
|
||||
// Software rendering
|
||||
Bitmap mSoftwareBitmap;
|
||||
ByteBuffer mSoftwareBuffer;
|
||||
Bitmap mSoftwareBufferCopy;
|
||||
|
||||
final SynchronousQueue<Object> mSyncDraws = new SynchronousQueue<Object>();
|
||||
}
|
||||
|
@ -1,227 +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/. */
|
||||
|
||||
#filter substitution
|
||||
package @ANDROID_PACKAGE_NAME@;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import org.json.*;
|
||||
|
||||
import org.mozilla.gecko.*;
|
||||
|
||||
import android.os.*;
|
||||
import android.content.*;
|
||||
import android.app.*;
|
||||
import android.text.*;
|
||||
import android.util.*;
|
||||
import android.widget.*;
|
||||
import android.database.sqlite.*;
|
||||
import android.database.*;
|
||||
import android.view.*;
|
||||
import android.net.Uri;
|
||||
import android.graphics.*;
|
||||
|
||||
|
||||
public class LauncherShortcuts extends Activity {
|
||||
|
||||
private ArrayList <HashMap<String, String>> mWebappsList;
|
||||
private File mWebappsFolder;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
setContentView(R.layout.launch_app_list);
|
||||
|
||||
final Intent intent = getIntent();
|
||||
final String action = intent.getAction();
|
||||
|
||||
if (Intent.ACTION_CREATE_SHORTCUT.equals(action)) {
|
||||
// Doing it as a background task, as it involves file access
|
||||
new FetchWebApps().execute();
|
||||
}
|
||||
}
|
||||
|
||||
public void onListItemClick(int id) {
|
||||
HashMap<String, String> map = mWebappsList.get(id);
|
||||
|
||||
String uri = map.get("uri").toString();
|
||||
String title = map.get("title").toString();
|
||||
String appKey = map.get("appKey").toString();
|
||||
String favicon = map.get("favicon").toString();
|
||||
|
||||
File manifestFile = new File(mWebappsFolder, appKey + "/manifest.json");
|
||||
|
||||
// Parse the contents into a string
|
||||
String manifestJson = new String();
|
||||
try {
|
||||
BufferedReader in = new BufferedReader(new FileReader(manifestFile));
|
||||
String line = new String();
|
||||
|
||||
while ((line = in.readLine()) != null) {
|
||||
manifestJson += line;
|
||||
}
|
||||
} catch (IOException e) { }
|
||||
|
||||
try {
|
||||
JSONObject manifest = (JSONObject) new JSONTokener(manifestJson).nextValue();
|
||||
uri += manifest.getString("launch_path");
|
||||
} catch (JSONException e) { }
|
||||
|
||||
Intent shortcutintent = new Intent("org.mozilla.gecko.WEBAPP");
|
||||
shortcutintent.setClass(this, App.class);
|
||||
shortcutintent.putExtra("args", "--webapp=" + uri);
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, title);
|
||||
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutintent);
|
||||
|
||||
DisplayMetrics dm = new DisplayMetrics();
|
||||
getWindowManager().getDefaultDisplay().getMetrics(dm);
|
||||
int size;
|
||||
switch (dm.densityDpi) {
|
||||
case DisplayMetrics.DENSITY_MEDIUM:
|
||||
size = 48;
|
||||
break;
|
||||
case DisplayMetrics.DENSITY_HIGH:
|
||||
size = 72;
|
||||
break;
|
||||
default:
|
||||
size = 72;
|
||||
}
|
||||
|
||||
Bitmap bitmap = BitmapFactory.decodeFile(favicon);
|
||||
if (bitmap != null) {
|
||||
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, size, size, true);
|
||||
intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, scaledBitmap);
|
||||
}
|
||||
|
||||
// Now, return the result to the launcher
|
||||
setResult(RESULT_OK, intent);
|
||||
finish();
|
||||
}
|
||||
|
||||
private class FetchWebApps extends AsyncTask<Void, Void, Void> {
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... unused) {
|
||||
mWebappsList = null;
|
||||
|
||||
Context context = getApplicationContext();
|
||||
|
||||
File home = new File(context.getFilesDir(), "mozilla");
|
||||
if (!home.exists())
|
||||
home = new File(context.getExternalFilesDir(null).getPath(), "mozilla");
|
||||
|
||||
if (!home.exists())
|
||||
return null;
|
||||
|
||||
File profile = null;
|
||||
String[] files = home.list();
|
||||
for (String file : files) {
|
||||
if (file.endsWith(".default")) {
|
||||
profile = new File(home, file);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (profile == null)
|
||||
return null;
|
||||
|
||||
// Save the folder path to be used during click event
|
||||
mWebappsFolder = new File(profile, "webapps");
|
||||
if (!mWebappsFolder.exists())
|
||||
return null;
|
||||
|
||||
File webapps = new File(mWebappsFolder, "webapps.json");
|
||||
if (!webapps.exists())
|
||||
return null;
|
||||
|
||||
// Parse the contents into a string
|
||||
String webappsJson = new String();
|
||||
try {
|
||||
BufferedReader in = new BufferedReader(new FileReader(webapps));
|
||||
String line = new String();
|
||||
|
||||
while ((line = in.readLine()) != null) {
|
||||
webappsJson += line;
|
||||
}
|
||||
} catch (IOException e) { }
|
||||
|
||||
if (webappsJson.length() == 0)
|
||||
return null;
|
||||
|
||||
mWebappsList = new ArrayList<HashMap<String, String>>();
|
||||
|
||||
try {
|
||||
JSONObject webApps = (JSONObject) new JSONTokener(webappsJson).nextValue();
|
||||
|
||||
Iterator<Object> appKeys = webApps.keys();
|
||||
HashMap<String, String> map;
|
||||
|
||||
while (appKeys.hasNext()) {
|
||||
String appKey = appKeys.next().toString();
|
||||
JSONObject app = webApps.getJSONObject(appKey);
|
||||
|
||||
map = new HashMap<String, String>();
|
||||
map.put("appKey", appKey);
|
||||
map.put("favicon", mWebappsFolder.getPath() + "/" + appKey + "/icon.png");
|
||||
map.put("title", app.getString("title"));
|
||||
map.put("uri", app.getString("appURI"));
|
||||
|
||||
mWebappsList.add(map);
|
||||
}
|
||||
|
||||
} catch (JSONException e) {}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void unused) {
|
||||
if (mWebappsList != null) {
|
||||
AlertDialog.Builder builder;
|
||||
|
||||
if (android.os.Build.VERSION.SDK_INT >= 11) {
|
||||
builder = new AlertDialog.Builder(LauncherShortcuts.this, AlertDialog.THEME_HOLO_LIGHT);
|
||||
} else {
|
||||
builder = new AlertDialog.Builder(LauncherShortcuts.this);
|
||||
}
|
||||
|
||||
builder.setTitle(R.string.launcher_shortcuts_title);
|
||||
builder.setAdapter(new SimpleAdapter(
|
||||
LauncherShortcuts.this,
|
||||
mWebappsList,
|
||||
R.layout.launch_app_listitem,
|
||||
new String[] { "favicon", "title" },
|
||||
new int[] { R.id.favicon, R.id.title }
|
||||
), new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
dialog.dismiss();
|
||||
onListItemClick(id);
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
|
||||
@Override
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
dialog.dismiss();
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
builder.create().show();
|
||||
} else {
|
||||
Toast.makeText(LauncherShortcuts.this, R.string.launcher_shortcuts_empty, Toast.LENGTH_LONG).show();
|
||||
finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,170 +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/.
|
||||
|
||||
DEPTH = @DEPTH@
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
include $(topsrcdir)/ipc/app/defs.mk
|
||||
|
||||
JAVAFILES = \
|
||||
GeckoApp.java \
|
||||
GeckoAppShell.java \
|
||||
GeckoConnectivityReceiver.java \
|
||||
GeckoEvent.java \
|
||||
GeckoSurfaceView.java \
|
||||
GeckoInputConnection.java \
|
||||
AlertNotification.java \
|
||||
SurfaceInfo.java \
|
||||
GeckoBatteryManager.java \
|
||||
VideoPlayer.java \
|
||||
GeckoNetworkManager.java \
|
||||
GeckoScreenOrientationListener.java \
|
||||
$(NULL)
|
||||
|
||||
ifdef MOZ_WEBSMS_BACKEND
|
||||
JAVAFILES += GeckoSmsManager.java
|
||||
endif
|
||||
|
||||
PROCESSEDJAVAFILES = \
|
||||
App.java \
|
||||
Restarter.java \
|
||||
NotificationHandler.java \
|
||||
LauncherShortcuts.java \
|
||||
SmsManager.java \
|
||||
$(NULL)
|
||||
|
||||
|
||||
ifneq (,$(findstring -march=armv7,$(OS_CFLAGS)))
|
||||
MIN_CPU_VERSION=7
|
||||
else
|
||||
MIN_CPU_VERSION=5
|
||||
endif
|
||||
|
||||
ifeq (,$(ANDROID_VERSION_CODE))
|
||||
# increment the version code by 1 so xul fennec will win any compatability ties
|
||||
ANDROID_VERSION_CODE=$(shell echo `$(PYTHON) $(topsrcdir)/toolkit/xre/make-platformini.py --print-buildid | cut -c1-10` + 1 | bc)
|
||||
endif
|
||||
|
||||
DEFINES += \
|
||||
-DANDROID_PACKAGE_NAME=$(ANDROID_PACKAGE_NAME) \
|
||||
-DMOZ_APP_DISPLAYNAME="$(MOZ_APP_DISPLAYNAME)" \
|
||||
-DMOZ_APP_NAME=$(MOZ_APP_NAME) \
|
||||
-DMOZ_APP_VERSION=$(MOZ_APP_VERSION) \
|
||||
-DMOZ_CHILD_PROCESS_NAME=$(MOZ_CHILD_PROCESS_NAME) \
|
||||
-DMOZ_MIN_CPU_VERSION=$(MIN_CPU_VERSION) \
|
||||
-DMOZ_CRASHREPORTER=$(MOZ_CRASHREPORTER) \
|
||||
-DANDROID_VERSION_CODE=$(ANDROID_VERSION_CODE) \
|
||||
-DMOZILLA_OFFICIAL=$(MOZILLA_OFFICIAL) \
|
||||
$(NULL)
|
||||
|
||||
GARBAGE += \
|
||||
AndroidManifest.xml \
|
||||
classes.dex \
|
||||
$(PROCESSEDJAVAFILES) \
|
||||
gecko.ap_ \
|
||||
res/values/strings.xml \
|
||||
R.java \
|
||||
$(NULL)
|
||||
|
||||
# Bug 567884 - Need a way to find appropriate icons during packaging
|
||||
ifeq ($(MOZ_APP_NAME),fennec)
|
||||
ICON_PATH = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/fennec_48x48.png
|
||||
ICON_PATH_HDPI = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/fennec_72x72.png
|
||||
|
||||
# we released these builds to the public with shared IDs and need to keep them
|
||||
ifeq (org.mozilla.firefox,$(ANDROID_PACKAGE_NAME))
|
||||
DEFINES += -DMOZ_ANDROID_SHARED_ID="org.mozilla.firefox.sharedID"
|
||||
else ifeq (org.mozilla.firefox_beta,$(ANDROID_PACKAGE_NAME))
|
||||
DEFINES += -DMOZ_ANDROID_SHARED_ID="org.mozilla.firefox.sharedID"
|
||||
else ifeq (org.mozilla.fennec_aurora,$(ANDROID_PACKAGE_NAME))
|
||||
DEFINES += -DMOZ_ANDROID_SHARED_ID="org.mozilla.fennec.sharedID"
|
||||
else ifeq (org.mozilla.fennec,$(ANDROID_PACKAGE_NAME))
|
||||
DEFINES += -DMOZ_ANDROID_SHARED_ID="org.mozilla.fennec.sharedID"
|
||||
endif
|
||||
|
||||
else
|
||||
ICON_PATH = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/icon48.png
|
||||
ICON_PATH_HDPI = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/icon64.png
|
||||
DEFINES += -DMOZ_ANDROID_SHARED_ID="$(ANDROID_PACKAGE_NAME).sharedID"
|
||||
endif
|
||||
|
||||
RES_LAYOUT = \
|
||||
res/layout/notification_progress.xml \
|
||||
res/layout/notification_progress_text.xml \
|
||||
res/layout/notification_icon_text.xml \
|
||||
res/layout/launch_app_list.xml \
|
||||
res/layout/launch_app_listitem.xml \
|
||||
res/layout/videoplayer.xml \
|
||||
$(NULL)
|
||||
|
||||
RES_VALUES = res/values/colors.xml res/values/themes.xml
|
||||
|
||||
JAVA_CLASSPATH = $(ANDROID_SDK)/android.jar
|
||||
|
||||
ifdef MOZ_CRASHREPORTER
|
||||
PROCESSEDJAVAFILES += CrashReporter.java
|
||||
MOZ_ANDROID_DRAWABLES += embedding/android/resources/drawable/crash_reporter.png
|
||||
RES_LAYOUT += res/layout/crash_reporter.xml
|
||||
endif
|
||||
|
||||
MOZ_ANDROID_DRAWABLES += embedding/android/resources/drawable/desktop_notification.png
|
||||
|
||||
MOZ_ANDROID_DRAWABLES += $(shell if test -e $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/android-resources.mn; then cat $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/android-resources.mn | tr '\n' ' '; fi)
|
||||
|
||||
RESOURCES=$(RES_LAYOUT) $(RES_VALUES)
|
||||
|
||||
RES_DIRS= \
|
||||
res/layout \
|
||||
res/values \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
# Override the Java settings with some specific android settings
|
||||
include $(topsrcdir)/config/android-common.mk
|
||||
|
||||
# Note that we're going to set up a dependency directly between embed_android.dex and the java files
|
||||
# Instead of on the .class files, since more than one .class file might be produced per .java file
|
||||
classes.dex: $(JAVAFILES) $(PROCESSEDJAVAFILES) R.java
|
||||
$(JAVAC) $(JAVAC_FLAGS) -d classes $(addprefix $(srcdir)/,$(JAVAFILES)) $(PROCESSEDJAVAFILES) R.java
|
||||
$(DX) --dex --output=$@ classes
|
||||
|
||||
AndroidManifest.xml $(PROCESSEDJAVAFILES): % : %.in
|
||||
$(PYTHON) $(topsrcdir)/config/Preprocessor.py \
|
||||
$(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $< > $@
|
||||
|
||||
res/drawable/icon.png: $(MOZ_APP_ICON)
|
||||
$(NSINSTALL) -D res/drawable
|
||||
cp $(ICON_PATH) $@
|
||||
|
||||
res/drawable-hdpi/icon.png: $(MOZ_APP_ICON)
|
||||
$(NSINSTALL) -D res/drawable-hdpi
|
||||
cp $(ICON_PATH_HDPI) $@
|
||||
|
||||
$(RES_DIRS):
|
||||
rm -rf $@
|
||||
$(NSINSTALL) -D $@
|
||||
|
||||
RES_DRAWABLE = $(addprefix res/drawable/,$(notdir $(MOZ_ANDROID_DRAWABLES)))
|
||||
|
||||
$(RES_DRAWABLE): $(addprefix $(topsrcdir)/,$(MOZ_ANDROID_DRAWABLES))
|
||||
$(NSINSTALL) -D res/drawable
|
||||
$(NSINSTALL) $^ res/drawable/
|
||||
|
||||
$(RESOURCES): $(RES_DIRS) $(subst res/,$(srcdir)/resources/,$(RESOURCES))
|
||||
@echo "creating $@"
|
||||
$(NSINSTALL) $(subst res/,$(srcdir)/resources/,$@) $(dir $@)
|
||||
|
||||
|
||||
R.java: $(MOZ_APP_ICON) $(RES_LAYOUT) $(RES_DRAWABLE) $(RES_VALUES) res/drawable/icon.png res/drawable-hdpi/icon.png AndroidManifest.xml chrome
|
||||
$(AAPT) package -f -M AndroidManifest.xml -I $(ANDROID_SDK)/android.jar -S res -J . --custom-package org.mozilla.gecko
|
||||
|
||||
gecko.ap_: AndroidManifest.xml res/drawable/icon.png res/drawable-hdpi/icon.png $(RES_LAYOUT) $(RES_DRAWABLE) $(RES_VALUES) res/values/strings.xml FORCE
|
||||
$(AAPT) package -f -M AndroidManifest.xml -I $(ANDROID_SDK)/android.jar -S res -F $@
|
||||
|
||||
libs:: classes.dex
|
||||
$(INSTALL) classes.dex $(FINAL_TARGET)
|
@ -1,72 +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/. */
|
||||
|
||||
#filter substitution
|
||||
package @ANDROID_PACKAGE_NAME@;
|
||||
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Intent;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.net.Uri;
|
||||
|
||||
public class NotificationHandler
|
||||
extends BroadcastReceiver
|
||||
{
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent != null)
|
||||
handleIntent(context, intent);
|
||||
}
|
||||
|
||||
protected void handleIntent(Context context, Intent notificationIntent) {
|
||||
String action = notificationIntent.getAction();
|
||||
String alertName = "";
|
||||
String alertCookie = "";
|
||||
Uri data = notificationIntent.getData();
|
||||
if (data != null) {
|
||||
alertName = data.getSchemeSpecificPart();
|
||||
alertCookie = data.getFragment();
|
||||
if (alertCookie == null)
|
||||
alertCookie = "";
|
||||
}
|
||||
|
||||
Log.i("GeckoAppJava", "NotificationHandler.handleIntent\n" +
|
||||
"- action = '" + action + "'\n" +
|
||||
"- alertName = '" + alertName + "'\n" +
|
||||
"- alertCookie = '" + alertCookie + "'");
|
||||
|
||||
int notificationID = alertName.hashCode();
|
||||
|
||||
Log.i("GeckoAppJava", "Handle notification ID " + notificationID);
|
||||
|
||||
if (App.mAppContext != null) {
|
||||
// This should call the observer, if any
|
||||
App.mAppContext.handleNotification(action, alertName, alertCookie);
|
||||
} else {
|
||||
// The app is not running, just cancel this notification
|
||||
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.cancel(notificationID);
|
||||
}
|
||||
|
||||
if (App.ACTION_ALERT_CLICK.equals(action)) {
|
||||
// Start or bring to front the main activity
|
||||
Intent appIntent = new Intent(Intent.ACTION_MAIN);
|
||||
appIntent.setClassName(context, "@ANDROID_PACKAGE_NAME@.App");
|
||||
appIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
appIntent.putExtra("args", "-alert " + alertName + (alertCookie.length() > 0 ? "#" + alertCookie : ""));
|
||||
try {
|
||||
Log.i("GeckoAppJava", "startActivity with intent: Action='" + appIntent.getAction() + "'" +
|
||||
", args='" + appIntent.getStringExtra("args") + "'" );
|
||||
context.startActivity(appIntent);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Log.e("GeckoAppJava", "NotificationHandler Exception: ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,62 +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/. */
|
||||
|
||||
#filter substitution
|
||||
package @ANDROID_PACKAGE_NAME@;
|
||||
|
||||
import android.app.*;
|
||||
import android.content.*;
|
||||
import android.util.*;
|
||||
import android.os.*;
|
||||
import java.io.*;
|
||||
import org.mozilla.gecko.GeckoAppShell;
|
||||
|
||||
public class Restarter extends Activity {
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
Log.i("Restarter", "trying to restart @MOZ_APP_NAME@");
|
||||
try {
|
||||
int countdown = 40;
|
||||
while (GeckoAppShell.checkForGeckoProcs() && --countdown > 0) {
|
||||
// Wait for the old process to die before we continue
|
||||
try {
|
||||
Thread.currentThread().sleep(100);
|
||||
} catch (InterruptedException ie) {}
|
||||
}
|
||||
|
||||
if (countdown <= 0) {
|
||||
// if the countdown expired, something is hung
|
||||
GeckoAppShell.killAnyZombies();
|
||||
countdown = 10;
|
||||
// wait for the kill to take effect
|
||||
while (GeckoAppShell.checkForGeckoProcs() && --countdown > 0) {
|
||||
try {
|
||||
Thread.currentThread().sleep(100);
|
||||
} catch (InterruptedException ie) {}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.i("Restarter", e.toString());
|
||||
}
|
||||
try {
|
||||
String action = "android.intent.action.MAIN";
|
||||
Intent intent = new Intent(action);
|
||||
intent.setClassName("@ANDROID_PACKAGE_NAME@",
|
||||
"@ANDROID_PACKAGE_NAME@.App");
|
||||
Bundle b = getIntent().getExtras();
|
||||
if (b != null)
|
||||
intent.putExtras(b);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
Log.i("GeckoAppJava", intent.toString());
|
||||
startActivity(intent);
|
||||
} catch (Exception e) {
|
||||
Log.i("Restarter", e.toString());
|
||||
}
|
||||
// Give the new process time to start before we die
|
||||
GeckoAppShell.waitForAnotherGeckoProc();
|
||||
System.exit(0);
|
||||
}
|
||||
};
|
@ -1,38 +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;
|
||||
|
||||
#ifdef MOZ_WEBSMS_BACKEND
|
||||
import org.mozilla.gecko.GeckoSmsManager;
|
||||
#endif
|
||||
|
||||
class SmsManager
|
||||
{
|
||||
static private ISmsManager sInstance = null;
|
||||
|
||||
static public ISmsManager getInstance() {
|
||||
#ifdef MOZ_WEBSMS_BACKEND
|
||||
if (sInstance == null) {
|
||||
sInstance = new GeckoSmsManager();
|
||||
}
|
||||
#endif
|
||||
return sInstance;
|
||||
}
|
||||
}
|
||||
|
||||
interface ISmsManager
|
||||
{
|
||||
public void start();
|
||||
public void stop();
|
||||
public void shutdown();
|
||||
|
||||
public void send(String aNumber, String aMessage, int aRequestId);
|
||||
public void getMessage(int aMessageId, int aRequestId);
|
||||
public void deleteMessage(int aMessageId, int aRequestId);
|
||||
public void createMessageList(long aStartDate, long aEndDate, String[] aNumbers, int aNumbersCount, int aDeliveryState, boolean aReverse, int aRequestId);
|
||||
public void getNextMessageInList(int aListId, int aRequestId);
|
||||
public void clearMessageList(int aListId);
|
||||
}
|
@ -1,11 +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;
|
||||
|
||||
public class SurfaceInfo {
|
||||
public int format;
|
||||
public int width;
|
||||
public int height;
|
||||
}
|
@ -1,42 +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/.
|
||||
|
||||
DEPTH = @DEPTH@
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
relativesrcdir = @relativesrcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
# special case some locale codes, he and id
|
||||
# http://code.google.com/p/android/issues/detail?id=3639
|
||||
AB_rCD = $(if $(filter he, $(AB_CD)),iw,$(if $(filter id, $(AB_CD)),in,$(subst -,-r,$(AB_CD))))
|
||||
|
||||
STRINGSPATH = $(call core_abspath,$(call MERGE_FILE,android_strings.dtd))
|
||||
ifeq (,$(XPI_NAME))
|
||||
BRANDPATH = $(call core_abspath,$(DEPTH)/dist/bin/chrome/$(AB_CD)/locale/branding/brand.dtd)
|
||||
else
|
||||
BRANDPATH = $(call core_abspath,$(DIST)/xpi-stage/$(XPI_NAME)/chrome/$(AB_CD)/locale/branding/brand.dtd)
|
||||
endif
|
||||
|
||||
DEFINES += -DAB_CD=$(AB_CD)
|
||||
|
||||
libs realchrome:: ../res/values/strings.xml ;
|
||||
|
||||
chrome-%:: AB_CD=$*
|
||||
chrome-%::
|
||||
@$(MAKE) ../res/values-$(AB_rCD)/strings.xml AB_CD=$*
|
||||
|
||||
%/strings.xml: FORCE
|
||||
$(NSINSTALL) -D $*
|
||||
# we don't have branding yet, but we need it. Call it explicitly
|
||||
@$(MAKE) -C $(DEPTH)/$(MOZ_BRANDING_DIRECTORY)/locales realchrome
|
||||
$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) \
|
||||
-DBRANDPATH="$(BRANDPATH)" \
|
||||
-DSTRINGSPATH="$(STRINGSPATH)" \
|
||||
$(srcdir)/../strings.xml.in \
|
||||
> $@
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
@ -1,25 +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/. -->
|
||||
|
||||
|
||||
<!ENTITY splash_firstrun "Setting up &brandShortName;\u2026">
|
||||
|
||||
<!ENTITY no_space_to_start_error "There is not enough space available for &brandShortName; to start.">
|
||||
<!ENTITY error_loading_file "An error occurred when trying to load files required to run &brandShortName;">
|
||||
|
||||
<!ENTITY crash_reporter_title "&brandShortName; Crash Reporter">
|
||||
<!ENTITY crash_message "&brandShortName; has crashed. Your tabs should be listed on the &brandShortName; Start page when you restart.">
|
||||
<!ENTITY crash_help_message "Please help us fix this problem!">
|
||||
<!ENTITY crash_send_report_message "Send Mozilla a crash report">
|
||||
<!ENTITY crash_include_url "Include page address">
|
||||
<!ENTITY crash_close_label "Close">
|
||||
<!ENTITY crash_restart_label "Restart &brandShortName;">
|
||||
<!ENTITY sending_crash_report "Sending crash report\u2026">
|
||||
<!ENTITY exit_label "Exit">
|
||||
<!ENTITY continue_label "Continue">
|
||||
|
||||
<!ENTITY launcher_shortcuts_title "&brandShortName; Web Apps">
|
||||
<!ENTITY launcher_shortcuts_empty "No web apps were found">
|
||||
|
||||
<!ENTITY choose_file "Choose File">
|
@ -1,9 +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/.
|
||||
|
||||
[general]
|
||||
depth = ../../..
|
||||
|
||||
[compare]
|
||||
dirs = embedding/android
|
@ -1,5 +0,0 @@
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
@ -1,6 +0,0 @@
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
DIRS += ['locales']
|
Binary file not shown.
Before Width: | Height: | Size: 2.8 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.8 KiB |
@ -1,52 +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/. -->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="10px" >
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10px"
|
||||
android:textStyle="bold"
|
||||
android:text="@string/crash_message"/>
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10px"
|
||||
android:text="@string/crash_help_message"/>
|
||||
<CheckBox android:id="@+id/send_report"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:checked="true"
|
||||
android:text="@string/crash_send_report_message" />
|
||||
<CheckBox android:id="@+id/include_url"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/crash_include_url" />
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:padding="10px"
|
||||
android:gravity="center_horizontal" >
|
||||
<Button android:id="@+id/close"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginRight="10px"
|
||||
android:minWidth="120sp"
|
||||
android:onClick="onCloseClick"
|
||||
android:text="@string/crash_close_label" />
|
||||
<Button android:id="@+id/restart"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10px"
|
||||
android:minWidth="120sp"
|
||||
android:onClick="onRestartClick"
|
||||
android:text="@string/crash_restart_label" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
@ -1,12 +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/. -->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="3dip"
|
||||
android:orientation="vertical"
|
||||
android:windowIsFloating="true">
|
||||
</LinearLayout>
|
@ -1,29 +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/. -->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?android:attr/listPreferredItemHeight"
|
||||
android:paddingLeft="16dip"
|
||||
android:paddingRight="16dip"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="left">
|
||||
<ImageView
|
||||
android:id="@+id/favicon"
|
||||
android:layout_width="48dip"
|
||||
android:layout_height="48dip"
|
||||
android:layout_marginRight="12dip"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="fitCenter"/>
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_vertical"
|
||||
android:textAppearance="?android:attr/textAppearanceLargeInverse"
|
||||
android:ellipsize="marquee"
|
||||
android:fadingEdge="horizontal"/>
|
||||
</LinearLayout>
|
@ -1,38 +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/. -->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="5dp"
|
||||
>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
<ImageView android:id="@+id/notificationImage"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="25dp"
|
||||
android:scaleType="fitCenter" />
|
||||
<TextView android:id="@+id/notificationTitle"
|
||||
android:textAppearance="@android:style/TextAppearance.StatusBar.EventContent.Title"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="marquee"
|
||||
android:fadingEdge="horizontal"
|
||||
android:paddingLeft="4dp"
|
||||
/>
|
||||
</LinearLayout>
|
||||
<TextView android:id="@+id/notificationText"
|
||||
android:textAppearance="@android:style/TextAppearance.StatusBar.EventContent"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="4dp"
|
||||
/>
|
||||
</LinearLayout>
|
@ -1,57 +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/. -->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="7dp"
|
||||
android:paddingLeft="5dp"
|
||||
>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
<ImageView android:id="@+id/notificationImage"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="25dp"
|
||||
android:scaleType="fitCenter" />
|
||||
<TextView android:id="@+id/notificationTitle"
|
||||
android:textAppearance="@android:style/TextAppearance.StatusBar.EventContent.Title"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="marquee"
|
||||
android:fadingEdge="horizontal"
|
||||
android:paddingLeft="10dp"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
<TextView android:id="@+id/notificationText"
|
||||
android:textAppearance="@android:style/TextAppearance.StatusBar.EventContent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="3dp"
|
||||
/>
|
||||
|
||||
<ProgressBar android:id="@+id/notificationProgressbar"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="1dip"
|
||||
android:layout_marginBottom="1dip"
|
||||
android:layout_marginLeft="4dip"
|
||||
android:layout_marginRight="10dip"
|
||||
android:layout_centerHorizontal="true" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
@ -1,50 +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/. -->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="5dp"
|
||||
>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
<ImageView android:id="@+id/notificationImage"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="25dp"
|
||||
android:scaleType="fitCenter" />
|
||||
<TextView android:id="@+id/notificationTitle"
|
||||
android:textAppearance="@android:style/TextAppearance.StatusBar.EventContent.Title"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="marquee"
|
||||
android:fadingEdge="horizontal"
|
||||
android:paddingLeft="4dp"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<ProgressBar android:id="@+id/notificationProgressbar"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="16dip"
|
||||
android:layout_marginTop="1dip"
|
||||
android:layout_marginBottom="1dip"
|
||||
android:layout_marginLeft="10dip"
|
||||
android:layout_marginRight="10dip"
|
||||
android:layout_centerHorizontal="true" />
|
||||
|
||||
<TextView android:id="@+id/notificationText"
|
||||
android:textAppearance="@android:style/TextAppearance.StatusBar.EventContent"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="4dp"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
@ -1,12 +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/. -->
|
||||
|
||||
<resources>
|
||||
<color name="splash_background">#000000</color>
|
||||
<color name="splash_msgfont">#ffffff</color>
|
||||
<color name="splash_urlfont">#000000</color>
|
||||
<color name="splash_content">#ffffff</color>
|
||||
</resources>
|
||||
|
@ -1,10 +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/. -->
|
||||
|
||||
<resources>
|
||||
<style name="GreyTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<item name="android:windowBackground">@color/splash_background</item>
|
||||
</style>
|
||||
</resources>
|
@ -1,31 +0,0 @@
|
||||
#filter substitution
|
||||
<?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/. -->
|
||||
|
||||
<!DOCTYPE resources [
|
||||
#includesubst @BRANDPATH@
|
||||
#includesubst @STRINGSPATH@
|
||||
]>
|
||||
<resources>
|
||||
<string name="splash_firstrun">&splash_firstrun;</string>
|
||||
<string name="no_space_to_start_error">&no_space_to_start_error;</string>
|
||||
<string name="error_loading_file">&error_loading_file;</string>
|
||||
|
||||
<string name="crash_reporter_title">&crash_reporter_title;</string>
|
||||
<string name="crash_message">&crash_message;</string>
|
||||
<string name="crash_help_message">&crash_help_message;</string>
|
||||
<string name="crash_send_report_message">&crash_send_report_message;</string>
|
||||
<string name="crash_include_url">&crash_include_url;</string>
|
||||
<string name="crash_close_label">&crash_close_label;</string>
|
||||
<string name="crash_restart_label">&crash_restart_label;</string>
|
||||
<string name="sending_crash_report">&sending_crash_report;</string>
|
||||
<string name="exit_label">&exit_label;</string>
|
||||
<string name="continue_label">&continue_label;</string>
|
||||
|
||||
<string name="launcher_shortcuts_title">&launcher_shortcuts_title;</string>
|
||||
<string name="launcher_shortcuts_empty">&launcher_shortcuts_empty;</string>
|
||||
|
||||
<string name="choose_file">&choose_file;</string>
|
||||
</resources>
|
@ -17,4 +17,3 @@ dirs = mobile mobile/android mobile/android/base
|
||||
[includes]
|
||||
toolkit = toolkit/locales/l10n.ini
|
||||
services_sync = services/sync/locales/l10n.ini
|
||||
embedding_android = embedding/android/locales/l10n.ini
|
||||
|
Loading…
Reference in New Issue
Block a user