Bug 650110 Update SUTAgent - adding in fencp, ffxcp, watcher code r=ctalbert

This commit is contained in:
Bob Moss 2011-04-18 11:55:24 -07:00
Родитель 4c4661970f
Коммит dfc437d211
45 изменённых файлов: 2863 добавлений и 1 удалений

Просмотреть файл

@ -72,7 +72,11 @@ endif
DIRS += pgo
ifeq (Android,$(OS_TARGET))
DIRS += mobile/sutagent/android
DIRS += mobile/sutagent/android \
mobile/sutagent/android/watcher \
mobile/sutagent/android/ffxcp \
mobile/sutagent/android/fencp \
$(NULL)
endif
include $(topsrcdir)/config/rules.mk

Просмотреть файл

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.mozilla.fencp"
android:versionCode="1"
android:versionName="1.0" android:sharedUserId="org.mozilla.fennec.sharedID">
<application android:icon="@drawable/icon" android:label="@string/app_name" android:debuggable="true">
<activity android:label="@string/app_name" android:name="FenCP">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider android:name="FenCPFP"
android:enabled="true"
android:authorities="org.mozilla.fencp"
android:exported="true">
</provider>
</application>
<uses-sdk android:minSdkVersion="6" />
</manifest>

Просмотреть файл

@ -0,0 +1,175 @@
package org.mozilla.fencp;
import java.io.File;
import java.io.IOException;
import android.database.MatrixCursor;
public class DirCursor extends MatrixCursor {
public static final String _ID = "_id";
public static final String ISDIR = "isdir";
public static final String FILENAME = "filename";
public static final String LENGTH = "length";
public static final String TIMESTAMP = "ts";
public static final String WRITABLE = "writable";
static final String[] DEFCOLUMNS = new String[] {
_ID,
ISDIR,
FILENAME,
LENGTH,
TIMESTAMP,
WRITABLE
};
private String dirPath = null;
private String [] theColumns = null;
public DirCursor(String[] columnNames, String sPath) {
super((columnNames == null ? DEFCOLUMNS : columnNames));
theColumns = (columnNames == null ? DEFCOLUMNS : columnNames);
dirPath = sPath;
doLoadCursor(dirPath);
}
public DirCursor(String[] columnNames, int initialCapacity, String sPath) {
super((columnNames == null ? DEFCOLUMNS : columnNames), initialCapacity);
theColumns = (columnNames == null ? DEFCOLUMNS : columnNames);
dirPath = sPath;
doLoadCursor(dirPath);
}
private void doLoadCursor(String sDir) {
File dir = new File(sDir);
int nFiles = 0;
int nCols = theColumns.length;
int lcvFiles = 0;
int nCIndex = 0;
Object [] vals = new Object[nCols];
if (vals == null)
return;
if (dir.isDirectory()) {
try {
nCIndex = getColumnIndex(_ID);
if (nCIndex > -1)
vals[nCIndex] = -1;
nCIndex = getColumnIndex(ISDIR);
if (nCIndex > -1)
vals[nCIndex] = 1;
nCIndex = getColumnIndex(FILENAME);
if (nCIndex > -1)
try {
vals[nCIndex] = dir.getCanonicalPath();
} catch (IOException e) {
vals[nCIndex] = dir.getName();
}
nCIndex = getColumnIndex(LENGTH);
if (nCIndex > -1)
vals[nCIndex] = 0;
nCIndex = getColumnIndex(TIMESTAMP);
if (nCIndex > -1)
vals[nCIndex] = 0;
nCIndex = getColumnIndex(WRITABLE);
if (nCIndex > -1)
vals[nCIndex] = (dir.canWrite() ? 1 : 0);
addRow(vals);
}
catch (IllegalArgumentException iae) {
iae.printStackTrace();
}
File [] files = dir.listFiles();
if (files != null) {
if ((nFiles = files.length) > 0) {
for (lcvFiles = 0; lcvFiles < nFiles; lcvFiles++) {
nCIndex = getColumnIndex(_ID);
if (nCIndex > -1)
vals[nCIndex] = lcvFiles;
nCIndex = getColumnIndex(ISDIR);
if (nCIndex > -1)
vals[nCIndex] = (files[lcvFiles].isDirectory() ? 1 : 0);
nCIndex = getColumnIndex(FILENAME);
if (nCIndex > -1)
vals[nCIndex] = files[lcvFiles].getName();
nCIndex = getColumnIndex(LENGTH);
if (nCIndex > -1)
vals[nCIndex] = (files[lcvFiles].isDirectory() ? -1 : files[lcvFiles].length());
try {
addRow(vals);
} catch (IllegalArgumentException iae) {
iae.printStackTrace();
}
}
}
}
} else {
if (dir.isFile()) {
nCIndex = getColumnIndex(_ID);
if (nCIndex > -1)
vals[nCIndex] = -1;
nCIndex = getColumnIndex(ISDIR);
if (nCIndex > -1)
vals[nCIndex] = 0;
nCIndex = getColumnIndex(FILENAME);
if (nCIndex > -1)
vals[nCIndex] = dir.getName();
nCIndex = getColumnIndex(LENGTH);
if (nCIndex > -1)
vals[nCIndex] = dir.length();
nCIndex = getColumnIndex(TIMESTAMP);
if (nCIndex > -1) {
vals[nCIndex] = dir.lastModified();
}
try {
addRow(vals);
}
catch (IllegalArgumentException iae) {
iae.printStackTrace();
}
}
else {
try {
nCIndex = getColumnIndex(_ID);
if (nCIndex > -1)
vals[nCIndex] = -1;
nCIndex = getColumnIndex(ISDIR);
if (nCIndex > -1)
vals[nCIndex] = 0;
nCIndex = getColumnIndex(FILENAME);
if (nCIndex > -1)
vals[nCIndex] = null;
nCIndex = getColumnIndex(LENGTH);
if (nCIndex > -1)
vals[nCIndex] = 0;
nCIndex = getColumnIndex(TIMESTAMP);
if (nCIndex > -1)
vals[nCIndex] = 0;
addRow(vals);
}
catch (IllegalArgumentException iae) {
iae.printStackTrace();
}
}
}
}
}

Просмотреть файл

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

Просмотреть файл

@ -0,0 +1,190 @@
package org.mozilla.fencp;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.net.Uri;
public class FenCPFP extends ContentProvider {
public static final String PROVIDER_NAME = "org.mozilla.fencp";
public static final Uri CONTENT_URI = Uri.parse("content://" + PROVIDER_NAME + "/file");
public static final String _ID = "_id";
public static final String ISDIR = "isdir";
public static final String FILENAME = "filename";
public static final String LENGTH = "length";
public static final String CHUNK = "chunk";
static String[] dircolumns = new String[] {
_ID,
ISDIR,
FILENAME,
LENGTH
};
static String[] filecolumns = new String[] {
_ID,
CHUNK
};
private static final int DIR = 1;
private static final int FILE_NAME = 2;
private static final UriMatcher uriMatcher;
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(PROVIDER_NAME, "dir", DIR);
uriMatcher.addURI(PROVIDER_NAME, "file", FILE_NAME);
}
public int PruneDir(String sTmpDir) {
int nRet = 0;
int nFiles = 0;
String sSubDir = null;
File dir = new File(sTmpDir);
if (dir.isDirectory()) {
File [] files = dir.listFiles();
if (files != null) {
if ((nFiles = files.length) > 0) {
for (int lcv = 0; lcv < nFiles; lcv++) {
if (files[lcv].isDirectory()) {
sSubDir = files[lcv].getAbsolutePath();
nRet += PruneDir(sSubDir);
}
else {
if (files[lcv].delete()) {
nRet++;
}
}
}
}
}
if (dir.delete()) {
nRet++;
}
if ((nFiles + 1) > nRet) {
nRet = -1;
}
}
return(nRet);
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int nFiles = 0;
switch (uriMatcher.match(uri)) {
case FILE_NAME:
File f = new File(selection);
if (f.delete())
nFiles = 1;
break;
case DIR:
nFiles = PruneDir(selection);
break;
default:
break;
}
return nFiles;
}
@Override
public String getType(Uri uri)
{
switch (uriMatcher.match(uri))
{
//---get directory---
case DIR:
return "vnd.android.cursor.dir/vnd.mozilla.dir ";
//---get a particular file---
case FILE_NAME:
return "vnd.android.cursor.item/vnd.mozilla.file ";
//---Unknown---
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
}
@Override
public Uri insert(Uri uri, ContentValues values) {
return null;
}
@Override
public boolean onCreate() {
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
Cursor retCursor = null;
switch(uriMatcher.match(uri)) {
case DIR:
retCursor = new DirCursor(projection, selection);
break;
case FILE_NAME:
retCursor = new FileCursor(projection, selection, selectionArgs);
break;
default:
break;
}
return (retCursor);
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
int nRet = 0;
FileOutputStream dstFile = null;
switch(uriMatcher.match(uri)) {
case DIR:
File dir = new File(selection);
if (dir.mkdirs())
nRet = 1;
break;
case FILE_NAME:
try {
long lOffset = values.getAsLong("offset");
byte [] buf = values.getAsByteArray(CHUNK);
int nLength = values.getAsInteger(LENGTH);
if ((buf != null) && (nLength > 0)) {
File f = new File(selection);
dstFile = new FileOutputStream(f, (lOffset == 0 ? false : true));
dstFile.write(buf,0, nLength);
dstFile.flush();
dstFile.close();
nRet = nLength;
}
} catch (FileNotFoundException fnfe) {
fnfe.printStackTrace();
} catch (IOException ioe) {
try {
dstFile.flush();
} catch (IOException e) {
}
try {
dstFile.close();
} catch (IOException e) {
}
}
break;
default:
break;
}
return nRet;
}
}

Просмотреть файл

@ -0,0 +1,166 @@
package org.mozilla.fencp;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import android.database.AbstractWindowedCursor;
import android.database.CursorWindow;
public class FileCursor extends AbstractWindowedCursor {
public static final String _ID = "_id";
public static final String CHUNK = "chunk";
public static final String LENGTH = "length";
static final String[] DEFCOLUMNS = new String[] {
_ID,
CHUNK,
LENGTH
};
private String filePath = null;
private String [] theColumns = null;
private static final int BUFSIZE = 4096;
private long lFileSize = 0;
private int nCount = 0;
private File theFile = null;
private byte [] theBuffer = null;
private long lOffset = 0;
private long lLength = -1;
public FileCursor(String[] columnNames, String sFilePath, String [] selectionArgs) {
super();
theColumns = (columnNames == null ? DEFCOLUMNS : columnNames);
filePath = sFilePath;
nCount = -1;
if ((selectionArgs != null) && (selectionArgs.length > 0)) {
lOffset = Long.parseLong(selectionArgs[0]);
lLength = Long.parseLong(selectionArgs[1]);
}
if (filePath.length() > 0) {
theFile = new File(filePath);
if (theFile.exists() && theFile.canRead()) {
lFileSize = theFile.length();
// lLength == -1 return everything between lOffset and eof
// lLength == 0 return file length
// lLength > 0 return lLength bytes
if (lLength == -1) {
lFileSize = lFileSize - lOffset;
} else if (lLength == 0) {
// just return the file length
} else {
lFileSize = ((lLength <= (lFileSize - lOffset)) ? lLength : (lFileSize - lOffset));
}
if (lLength != 0) {
nCount = (int) (lFileSize / BUFSIZE);
if ((lFileSize % BUFSIZE) > 0)
nCount++;
} else {
nCount = 1;
}
mRowIdColumnIndex = 0;
}
}
}
public String getColumnName (int columnIndex) {
return theColumns[columnIndex];
}
@Override
public String[] getColumnNames() {
return theColumns;
}
@Override
public int getCount() {
return nCount;
}
@Override
public boolean onMove(int oldPosition, int newPosition) {
boolean bRet = true;
// get rid of old data
mWindow.clear();
bRet = mWindow.setNumColumns(theColumns.length);
fillWindow(newPosition, mWindow);
return bRet;
}
@Override
public void fillWindow (int pos, CursorWindow window) {
int nNumRows = window.getNumRows();
int nCIndex = 0;
window.setStartPosition(0);
if (pos > -1) {
if (nNumRows == 0) {
window.allocRow();
nNumRows = window.getNumRows();
}
if (nNumRows == 1) {
nCIndex = getColumnIndex(LENGTH);
if (nCIndex > -1) {
window.putLong(lFileSize, 0, nCIndex);
}
nCIndex = getColumnIndex(_ID);
if (nCIndex > -1) {
window.putLong((long)pos, 0, nCIndex);
}
nCIndex = getColumnIndex(CHUNK);
if (nCIndex > -1) {
if (lLength != 0) {
byte[] value = getABlob (pos, 1);
window.putBlob(value, 0, nCIndex);
}
}
}
window.setStartPosition(pos);
}
return;
}
public byte[] getABlob (int row, int column) {
int nRead = 0;
int nOffset = 0;
int nBufSize = 0;
if ((column == 1) && (theFile != null)) {
try {
FileInputStream fin = new FileInputStream(theFile);
nOffset = row * BUFSIZE;
if (row < (nCount - 1)) {
nBufSize = BUFSIZE;
} else {
nBufSize = (int) (lFileSize - nOffset);
}
theBuffer = new byte[nBufSize];
if (theBuffer != null) {
if (fin.skip(nOffset + lOffset) == (nOffset + lOffset)) {
if ((nRead = fin.read(theBuffer, 0, nBufSize)) != -1) {
if (nRead != nBufSize) {
return null;
}
}
}
}
fin.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
return theBuffer;
}
}

Просмотреть файл

@ -0,0 +1,103 @@
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is the Android sutagent for testing.
#
# The Initial Developer of the Original Code is
# Mozilla Foundation
# Portions created by the Initial Developer are Copyright (C) 2010
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Clint Talbert <ctalbert@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = FenCP
JAVAFILES = \
DirCursor.java \
FenCP.java \
FenCPFP.java \
FileCursor.java \
R.java \
$(NULL)
RES_FILES = \
res/drawable-hdpi/icon.png \
res/drawable-ldpi/icon.png \
res/drawable-mdpi/icon.png \
res/layout/main.xml \
res/values/strings.xml \
$(NULL)
GARBAGE += \
AndroidManifest.xml \
classes.dex \
FenCP.apk \
$(NULL)
GARBAGE_DIRS += res classes network-libs
JAVA_CLASSPATH = $(ANDROID_SDK)/android.jar
include $(topsrcdir)/config/rules.mk
# include Android specific java flags - using these instead of what's in rules.mk
include $(topsrcdir)/config/android-common.mk
tools:: FenCP.apk
classes.dex: $(JAVAFILES)
$(NSINSTALL) -D classes
$(JAVAC) $(JAVAC_FLAGS) -d classes $(addprefix $(srcdir)/,$(JAVAFILES))
$(DX) --dex --output=$@ classes
FenCP.ap_: $(srcdir)/AndroidManifest.xml
$(AAPT) package -f -M $(srcdir)/AndroidManifest.xml -I $(ANDROID_SDK)/android.jar -S res -F $@
FenCP-unsigned-unaligned.apk: FenCP.ap_ classes.dex
$(APKBUILDER) $@ -v $(APKBUILDER_FLAGS) -z FenCP.ap_ -f classes.dex
FenCP-unaligned.apk: FenCP-unsigned-unaligned.apk
cp FenCP-unsigned-unaligned.apk $@
ifdef JARSIGNER
$(JARSIGNER) $@
endif
FenCP.apk: FenCP-unaligned.apk
$(ZIPALIGN) -f -v 4 FenCP-unaligned.apk $@
export::
$(NSINSTALL) -D res
@(cd $(srcdir)/res && tar $(TAR_CREATE_FLAGS) - *) | (cd $(DEPTH)/build/mobile/sutagent/android/fencp/res && tar -xf -)

Просмотреть файл

@ -0,0 +1,23 @@
/* AUTO-GENERATED FILE. DO NOT MODIFY.
*
* This class was automatically generated by the
* aapt tool from the resource data it found. It
* should not be modified by hand.
*/
package org.mozilla.fencp;
public final class R {
public static final class attr {
}
public static final class drawable {
public static final int icon=0x7f020000;
}
public static final class layout {
public static final int main=0x7f030000;
}
public static final class string {
public static final int app_name=0x7f040001;
public static final int hello=0x7f040000;
}
}

Просмотреть файл

@ -0,0 +1,11 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system use,
# "build.properties", and override values to adapt the script to your
# project structure.
# Project target.
target=android-6

Двоичные данные
build/mobile/sutagent/android/fencp/res/drawable-hdpi/icon.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 4.0 KiB

Двоичные данные
build/mobile/sutagent/android/fencp/res/drawable-ldpi/icon.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.7 KiB

Двоичные данные
build/mobile/sutagent/android/fencp/res/drawable-mdpi/icon.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.5 KiB

Просмотреть файл

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
</LinearLayout>

Просмотреть файл

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello World, FennecCP!</string>
<string name="app_name">FennecCP</string>
</resources>

Просмотреть файл

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.mozilla.ffxcp"
android:versionCode="1"
android:versionName="1.0" android:sharedUserId="org.mozilla.firefox.sharedID">
<application android:icon="@drawable/icon" android:label="@string/app_name" android:debuggable="true">
<activity android:label="@string/app_name" android:name="ffxcp">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider android:name="FfxCPFP"
android:enabled="true"
android:authorities="org.mozilla.ffxcp"
android:exported="true">
</provider>
</application>
<uses-sdk android:minSdkVersion="6" />
</manifest>

Просмотреть файл

@ -0,0 +1,175 @@
package org.mozilla.ffxcp;
import java.io.File;
import java.io.IOException;
import android.database.MatrixCursor;
public class DirCursor extends MatrixCursor {
public static final String _ID = "_id";
public static final String ISDIR = "isdir";
public static final String FILENAME = "filename";
public static final String LENGTH = "length";
public static final String TIMESTAMP = "ts";
public static final String WRITABLE = "writable";
static final String[] DEFCOLUMNS = new String[] {
_ID,
ISDIR,
FILENAME,
LENGTH,
TIMESTAMP,
WRITABLE
};
private String dirPath = null;
private String [] theColumns = null;
public DirCursor(String[] columnNames, String sPath) {
super((columnNames == null ? DEFCOLUMNS : columnNames));
theColumns = (columnNames == null ? DEFCOLUMNS : columnNames);
dirPath = sPath;
doLoadCursor(dirPath);
}
public DirCursor(String[] columnNames, int initialCapacity, String sPath) {
super((columnNames == null ? DEFCOLUMNS : columnNames), initialCapacity);
theColumns = (columnNames == null ? DEFCOLUMNS : columnNames);
dirPath = sPath;
doLoadCursor(dirPath);
}
private void doLoadCursor(String sDir) {
File dir = new File(sDir);
int nFiles = 0;
int nCols = theColumns.length;
int lcvFiles = 0;
int nCIndex = 0;
Object [] vals = new Object[nCols];
if (vals == null)
return;
if (dir.isDirectory()) {
try {
nCIndex = getColumnIndex(_ID);
if (nCIndex > -1)
vals[nCIndex] = -1;
nCIndex = getColumnIndex(ISDIR);
if (nCIndex > -1)
vals[nCIndex] = 1;
nCIndex = getColumnIndex(FILENAME);
if (nCIndex > -1)
try {
vals[nCIndex] = dir.getCanonicalPath();
} catch (IOException e) {
vals[nCIndex] = dir.getName();
}
nCIndex = getColumnIndex(LENGTH);
if (nCIndex > -1)
vals[nCIndex] = 0;
nCIndex = getColumnIndex(TIMESTAMP);
if (nCIndex > -1)
vals[nCIndex] = 0;
nCIndex = getColumnIndex(WRITABLE);
if (nCIndex > -1)
vals[nCIndex] = (dir.canWrite() ? 1 : 0);
addRow(vals);
}
catch (IllegalArgumentException iae) {
iae.printStackTrace();
}
File [] files = dir.listFiles();
if (files != null) {
if ((nFiles = files.length) > 0) {
for (lcvFiles = 0; lcvFiles < nFiles; lcvFiles++) {
nCIndex = getColumnIndex(_ID);
if (nCIndex > -1)
vals[nCIndex] = lcvFiles;
nCIndex = getColumnIndex(ISDIR);
if (nCIndex > -1)
vals[nCIndex] = (files[lcvFiles].isDirectory() ? 1 : 0);
nCIndex = getColumnIndex(FILENAME);
if (nCIndex > -1)
vals[nCIndex] = files[lcvFiles].getName();
nCIndex = getColumnIndex(LENGTH);
if (nCIndex > -1)
vals[nCIndex] = (files[lcvFiles].isDirectory() ? -1 : files[lcvFiles].length());
try {
addRow(vals);
} catch (IllegalArgumentException iae) {
iae.printStackTrace();
}
}
}
}
} else {
if (dir.isFile()) {
nCIndex = getColumnIndex(_ID);
if (nCIndex > -1)
vals[nCIndex] = -1;
nCIndex = getColumnIndex(ISDIR);
if (nCIndex > -1)
vals[nCIndex] = 0;
nCIndex = getColumnIndex(FILENAME);
if (nCIndex > -1)
vals[nCIndex] = dir.getName();
nCIndex = getColumnIndex(LENGTH);
if (nCIndex > -1)
vals[nCIndex] = dir.length();
nCIndex = getColumnIndex(TIMESTAMP);
if (nCIndex > -1) {
vals[nCIndex] = dir.lastModified();
}
try {
addRow(vals);
}
catch (IllegalArgumentException iae) {
iae.printStackTrace();
}
}
else {
try {
nCIndex = getColumnIndex(_ID);
if (nCIndex > -1)
vals[nCIndex] = -1;
nCIndex = getColumnIndex(ISDIR);
if (nCIndex > -1)
vals[nCIndex] = 0;
nCIndex = getColumnIndex(FILENAME);
if (nCIndex > -1)
vals[nCIndex] = null;
nCIndex = getColumnIndex(LENGTH);
if (nCIndex > -1)
vals[nCIndex] = 0;
nCIndex = getColumnIndex(TIMESTAMP);
if (nCIndex > -1)
vals[nCIndex] = 0;
addRow(vals);
}
catch (IllegalArgumentException iae) {
iae.printStackTrace();
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,190 @@
package org.mozilla.ffxcp;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.net.Uri;
public class FfxCPFP extends ContentProvider {
public static final String PROVIDER_NAME = "org.mozilla.ffxcp";
public static final Uri CONTENT_URI = Uri.parse("content://" + PROVIDER_NAME + "/file");
public static final String _ID = "_id";
public static final String ISDIR = "isdir";
public static final String FILENAME = "filename";
public static final String LENGTH = "length";
public static final String CHUNK = "chunk";
static String[] dircolumns = new String[] {
_ID,
ISDIR,
FILENAME,
LENGTH
};
static String[] filecolumns = new String[] {
_ID,
CHUNK
};
private static final int DIR = 1;
private static final int FILE_NAME = 2;
private static final UriMatcher uriMatcher;
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(PROVIDER_NAME, "dir", DIR);
uriMatcher.addURI(PROVIDER_NAME, "file", FILE_NAME);
}
public int PruneDir(String sTmpDir) {
int nRet = 0;
int nFiles = 0;
String sSubDir = null;
File dir = new File(sTmpDir);
if (dir.isDirectory()) {
File [] files = dir.listFiles();
if (files != null) {
if ((nFiles = files.length) > 0) {
for (int lcv = 0; lcv < nFiles; lcv++) {
if (files[lcv].isDirectory()) {
sSubDir = files[lcv].getAbsolutePath();
nRet += PruneDir(sSubDir);
}
else {
if (files[lcv].delete()) {
nRet++;
}
}
}
}
}
if (dir.delete()) {
nRet++;
}
if ((nFiles + 1) > nRet) {
nRet = -1;
}
}
return(nRet);
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int nFiles = 0;
switch (uriMatcher.match(uri)) {
case FILE_NAME:
File f = new File(selection);
if (f.delete())
nFiles = 1;
break;
case DIR:
nFiles = PruneDir(selection);
break;
default:
break;
}
return nFiles;
}
@Override
public String getType(Uri uri)
{
switch (uriMatcher.match(uri))
{
//---get directory---
case DIR:
return "vnd.android.cursor.dir/vnd.mozilla.dir ";
//---get a particular file---
case FILE_NAME:
return "vnd.android.cursor.item/vnd.mozilla.file ";
//---Unknown---
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
}
@Override
public Uri insert(Uri uri, ContentValues values) {
return null;
}
@Override
public boolean onCreate() {
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
Cursor retCursor = null;
switch(uriMatcher.match(uri)) {
case DIR:
retCursor = new DirCursor(projection, selection);
break;
case FILE_NAME:
retCursor = new FileCursor(projection, selection, selectionArgs);
break;
default:
break;
}
return (retCursor);
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
int nRet = 0;
FileOutputStream dstFile = null;
switch(uriMatcher.match(uri)) {
case DIR:
File dir = new File(selection);
if (dir.mkdirs())
nRet = 1;
break;
case FILE_NAME:
try {
long lOffset = values.getAsLong("offset");
byte [] buf = values.getAsByteArray(CHUNK);
int nLength = values.getAsInteger(LENGTH);
if ((buf != null) && (nLength > 0)) {
File f = new File(selection);
dstFile = new FileOutputStream(f, (lOffset == 0 ? false : true));
dstFile.write(buf,0, nLength);
dstFile.flush();
dstFile.close();
nRet = nLength;
}
} catch (FileNotFoundException fnfe) {
fnfe.printStackTrace();
} catch (IOException ioe) {
try {
dstFile.flush();
} catch (IOException e) {
}
try {
dstFile.close();
} catch (IOException e) {
}
}
break;
default:
break;
}
return nRet;
}
}

Просмотреть файл

@ -0,0 +1,167 @@
package org.mozilla.ffxcp;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import android.database.AbstractWindowedCursor;
import android.database.CursorWindow;
public class FileCursor extends AbstractWindowedCursor {
public static final String _ID = "_id";
public static final String CHUNK = "chunk";
public static final String LENGTH = "length";
static final String[] DEFCOLUMNS = new String[] {
_ID,
CHUNK,
LENGTH
};
private String filePath = null;
private String [] theColumns = null;
private static final int BUFSIZE = 4096;
private long lFileSize = 0;
private int nCount = 0;
private File theFile = null;
private byte [] theBuffer = null;
private long lOffset = 0;
private long lLength = -1;
public FileCursor(String[] columnNames, String sFilePath, String [] selectionArgs) {
super();
theColumns = (columnNames == null ? DEFCOLUMNS : columnNames);
filePath = sFilePath;
nCount = -1;
if ((selectionArgs != null) && (selectionArgs.length > 0)) {
lOffset = Long.parseLong(selectionArgs[0]);
lLength = Long.parseLong(selectionArgs[1]);
}
if (filePath.length() > 0) {
theFile = new File(filePath);
if (theFile.exists() && theFile.canRead()) {
lFileSize = theFile.length();
// lLength == -1 return everything between lOffset and eof
// lLength == 0 return file length
// lLength > 0 return lLength bytes
if (lLength == -1) {
lFileSize = lFileSize - lOffset;
} else if (lLength == 0) {
// just return the file length
} else {
lFileSize = ((lLength <= (lFileSize - lOffset)) ? lLength : (lFileSize - lOffset));
}
if (lLength != 0) {
nCount = (int) (lFileSize / BUFSIZE);
if ((lFileSize % BUFSIZE) > 0)
nCount++;
} else {
nCount = 1;
}
mRowIdColumnIndex = 0;
}
}
}
public String getColumnName (int columnIndex) {
return theColumns[columnIndex];
}
@Override
public String[] getColumnNames() {
return theColumns;
}
@Override
public int getCount() {
return nCount;
}
@Override
public boolean onMove(int oldPosition, int newPosition) {
boolean bRet = true;
// get rid of old data
mWindow.clear();
bRet = mWindow.setNumColumns(theColumns.length);
fillWindow(newPosition, mWindow);
return bRet;
}
@Override
public void fillWindow (int pos, CursorWindow window) {
int nNumRows = window.getNumRows();
int nCIndex = 0;
window.setStartPosition(0);
if (pos > -1) {
if (nNumRows == 0) {
window.allocRow();
nNumRows = window.getNumRows();
}
if (nNumRows == 1) {
nCIndex = getColumnIndex(LENGTH);
if (nCIndex > -1) {
window.putLong(lFileSize, 0, nCIndex);
}
nCIndex = getColumnIndex(_ID);
if (nCIndex > -1) {
window.putLong((long)pos, 0, nCIndex);
}
nCIndex = getColumnIndex(CHUNK);
if (nCIndex > -1) {
if (lLength != 0) {
byte[] value = getABlob (pos, 1);
window.putBlob(value, 0, nCIndex);
}
}
}
window.setStartPosition(pos);
}
return;
}
public byte[] getABlob (int row, int column) {
int nRead = 0;
int nOffset = 0;
int nBufSize = 0;
if ((column == 1) && (theFile != null)) {
try {
FileInputStream fin = new FileInputStream(theFile);
nOffset = row * BUFSIZE;
if (row < (nCount - 1)) {
nBufSize = BUFSIZE;
} else {
nBufSize = (int) (lFileSize - nOffset);
}
theBuffer = new byte[nBufSize];
if (theBuffer != null) {
if (fin.skip(nOffset + lOffset) == (nOffset + lOffset)) {
if ((nRead = fin.read(theBuffer, 0, nBufSize)) != -1) {
if (nRead != nBufSize) {
return null;
}
}
}
}
fin.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
return theBuffer;
}
}

Просмотреть файл

@ -0,0 +1,103 @@
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is the Android sutagent for testing.
#
# The Initial Developer of the Original Code is
# Mozilla Foundation
# Portions created by the Initial Developer are Copyright (C) 2010
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Clint Talbert <ctalbert@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = FfxCP
JAVAFILES = \
DirCursor.java \
ffxcp.java \
FfxCPFP.java \
FileCursor.java \
R.java \
$(NULL)
RES_FILES = \
res/drawable-hdpi/icon.png \
res/drawable-ldpi/icon.png \
res/drawable-mdpi/icon.png \
res/layout/main.xml \
res/values/strings.xml \
$(NULL)
GARBAGE += \
AndroidManifest.xml \
classes.dex \
FfxCP.apk \
$(NULL)
GARBAGE_DIRS += res classes network-libs
JAVA_CLASSPATH = $(ANDROID_SDK)/android.jar
include $(topsrcdir)/config/rules.mk
# include Android specific java flags - using these instead of what's in rules.mk
include $(topsrcdir)/config/android-common.mk
tools:: FfxCP.apk
classes.dex: $(JAVAFILES)
$(NSINSTALL) -D classes
$(JAVAC) $(JAVAC_FLAGS) -d classes $(addprefix $(srcdir)/,$(JAVAFILES))
$(DX) --dex --output=$@ classes
FfxCP.ap_: $(srcdir)/AndroidManifest.xml
$(AAPT) package -f -M $(srcdir)/AndroidManifest.xml -I $(ANDROID_SDK)/android.jar -S res -F $@
FfxCP-unsigned-unaligned.apk: FfxCP.ap_ classes.dex
$(APKBUILDER) $@ -v $(APKBUILDER_FLAGS) -z FfxCP.ap_ -f classes.dex
FfxCP-unaligned.apk: FfxCP-unsigned-unaligned.apk
cp FfxCP-unsigned-unaligned.apk $@
ifdef JARSIGNER
$(JARSIGNER) $@
endif
FfxCP.apk: FfxCP-unaligned.apk
$(ZIPALIGN) -f -v 4 FfxCP-unaligned.apk $@
export::
$(NSINSTALL) -D res
@(cd $(srcdir)/res && tar $(TAR_CREATE_FLAGS) - *) | (cd $(DEPTH)/build/mobile/sutagent/android/ffxcp/res && tar -xf -)

Просмотреть файл

@ -0,0 +1,23 @@
/* AUTO-GENERATED FILE. DO NOT MODIFY.
*
* This class was automatically generated by the
* aapt tool from the resource data it found. It
* should not be modified by hand.
*/
package org.mozilla.ffxcp;
public final class R {
public static final class attr {
}
public static final class drawable {
public static final int icon=0x7f020000;
}
public static final class layout {
public static final int main=0x7f030000;
}
public static final class string {
public static final int app_name=0x7f040001;
public static final int hello=0x7f040000;
}
}

Просмотреть файл

@ -0,0 +1,11 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system use,
# "build.properties", and override values to adapt the script to your
# project structure.
# Project target.
target=android-6

Просмотреть файл

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

Двоичные данные
build/mobile/sutagent/android/ffxcp/res/drawable-hdpi/icon.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 4.0 KiB

Двоичные данные
build/mobile/sutagent/android/ffxcp/res/drawable-ldpi/icon.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.7 KiB

Двоичные данные
build/mobile/sutagent/android/ffxcp/res/drawable-mdpi/icon.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.5 KiB

Просмотреть файл

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
</LinearLayout>

Просмотреть файл

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello World, firefoxcp!</string>
<string name="app_name">FirefoxCP</string>
</resources>

Просмотреть файл

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mozilla.watcher"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".WatcherMain"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".WatcherReceiver">
<intent-filter>
<action android:value="android.intent.action.BOOT_COMPLETED" android:name="android.intent.action.BOOT_COMPLETED"/>
<category android:value="android.intent.category.HOME" android:name="android.intent.category.HOME"/>
</intent-filter>
</receiver>
<service android:name="WatcherService">
<intent-filter>
<action android:name="com.mozilla.watcher.LISTENER_SERVICE" />
</intent-filter>
</service>
</application>
<uses-sdk android:minSdkVersion="5" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD"></uses-permission>
<uses-permission android:name="android.permission.WAKE_LOCK"></uses-permission>
<uses-permission android:name="android.permission.VIBRATE"></uses-permission>
</manifest>

Просмотреть файл

@ -0,0 +1,104 @@
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: C:\\Users\\Bob\\workspace\\Watcher\\src\\com\\mozilla\\watcher\\IWatcherService.aidl
*/
package com.mozilla.watcher;
public interface IWatcherService extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.mozilla.watcher.IWatcherService
{
private static final java.lang.String DESCRIPTOR = "com.mozilla.watcher.IWatcherService";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.mozilla.watcher.IWatcherService interface,
* generating a proxy if needed.
*/
public static com.mozilla.watcher.IWatcherService asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.mozilla.watcher.IWatcherService))) {
return ((com.mozilla.watcher.IWatcherService)iin);
}
return new com.mozilla.watcher.IWatcherService.Stub.Proxy(obj);
}
public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_UpdateApplication:
{
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
java.lang.String _arg1;
_arg1 = data.readString();
java.lang.String _arg2;
_arg2 = data.readString();
int _arg3;
_arg3 = data.readInt();
int _result = this.UpdateApplication(_arg0, _arg1, _arg2, _arg3);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.mozilla.watcher.IWatcherService
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
public int UpdateApplication(java.lang.String sPkgName, java.lang.String sPkgFileName, java.lang.String sOutFile, int bReboot) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(sPkgName);
_data.writeString(sPkgFileName);
_data.writeString(sOutFile);
_data.writeInt(bReboot);
mRemote.transact(Stub.TRANSACTION_UpdateApplication, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_UpdateApplication = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public int UpdateApplication(java.lang.String sPkgName, java.lang.String sPkgFileName, java.lang.String sOutFile, int bReboot) throws android.os.RemoteException;
}

Просмотреть файл

@ -0,0 +1,107 @@
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is the Android sutagent for testing.
#
# The Initial Developer of the Original Code is
# Mozilla Foundation
# Portions created by the Initial Developer are Copyright (C) 2010
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Clint Talbert <ctalbert@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = Watcher
JAVAFILES = \
IWatcherService.java \
RedirOutputThread.java \
R.java \
WatcherMain.java \
WatcherReceiver.java \
WatcherService.java \
$(NULL)
RES_FILES = \
res/drawable-hdpi/icon.png \
res/drawable-hdpi/ateamlogo.png \
res/drawable-ldpi/icon.png \
res/drawable-ldpi/ateamlogo.png \
res/drawable-mdpi/icon.png \
res/drawable-mdpi/ateamlogo.png \
res/layout/main.xml \
res/values/strings.xml \
$(NULL)
GARBAGE += \
AndroidManifest.xml \
classes.dex \
Watcher.apk \
$(NULL)
GARBAGE_DIRS += res classes network-libs
JAVA_CLASSPATH = $(ANDROID_SDK)/android.jar
include $(topsrcdir)/config/rules.mk
# include Android specific java flags - using these instead of what's in rules.mk
include $(topsrcdir)/config/android-common.mk
tools:: Watcher.apk
classes.dex: $(JAVAFILES)
$(NSINSTALL) -D classes
$(JAVAC) $(JAVAC_FLAGS) -d classes $(addprefix $(srcdir)/,$(JAVAFILES))
$(DX) --dex --output=$@ classes
Watcher.ap_: $(srcdir)/AndroidManifest.xml
$(AAPT) package -f -M $(srcdir)/AndroidManifest.xml -I $(ANDROID_SDK)/android.jar -S res -F $@
Watcher-unsigned-unaligned.apk: Watcher.ap_ classes.dex
$(APKBUILDER) $@ -v $(APKBUILDER_FLAGS) -z Watcher.ap_ -f classes.dex
Watcher-unaligned.apk: Watcher-unsigned-unaligned.apk
cp Watcher-unsigned-unaligned.apk $@
ifdef JARSIGNER
$(JARSIGNER) $@
endif
Watcher.apk: Watcher-unaligned.apk
$(ZIPALIGN) -f -v 4 Watcher-unaligned.apk $@
export::
$(NSINSTALL) -D res
@(cd $(srcdir)/res && tar $(TAR_CREATE_FLAGS) - *) | (cd $(DEPTH)/build/mobile/sutagent/android/watcher/res && tar -xf -)

Просмотреть файл

@ -0,0 +1,25 @@
/* AUTO-GENERATED FILE. DO NOT MODIFY.
*
* This class was automatically generated by the
* aapt tool from the resource data it found. It
* should not be modified by hand.
*/
package com.mozilla.watcher;
public final class R {
public static final class attr {
}
public static final class drawable {
public static final int ateamlogo=0x7f020000;
public static final int icon=0x7f020001;
}
public static final class layout {
public static final int main=0x7f030000;
}
public static final class string {
public static final int app_name=0x7f040001;
public static final int foreground_service_started=0x7f040002;
public static final int hello=0x7f040000;
}
}

Просмотреть файл

@ -0,0 +1,164 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Android SUTAgent code.
*
* The Initial Developer of the Original Code is
* Bob Moss.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Bob Moss <bmoss@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package com.mozilla.watcher;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
public class RedirOutputThread extends Thread
{
OutputStream out;
InputStream sutErr;
InputStream sutOut;
Process pProc;
String strOutput;
public RedirOutputThread(Process pProc, OutputStream out)
{
if (pProc != null)
{
this.pProc = pProc;
sutErr = pProc.getErrorStream(); // Stderr
sutOut = pProc.getInputStream(); // Stdout
}
if (out != null)
this.out = out;
strOutput = "";
}
public void run()
{
boolean bStillRunning = true;
int nBytesOut = 0;
int nBytesErr = 0;
int nBytesRead = 0;
PrintWriter pOut = null;
byte[] buffer = new byte[1024];
if (out != null)
pOut = new PrintWriter(out);
else
bStillRunning = true;
while (bStillRunning)
{
try
{
if ((nBytesOut = sutOut.available()) > 0)
{
if (nBytesOut > buffer.length)
{
buffer = null;
System.gc();
buffer = new byte[nBytesOut];
}
nBytesRead = sutOut.read(buffer, 0, nBytesOut);
if (nBytesRead == -1)
bStillRunning = false;
else
{
String sRep = new String(buffer,0,nBytesRead).replace("\n", "\r\n");
if (pOut != null)
{
pOut.print(sRep);
pOut.flush();
}
else
strOutput += sRep;
}
}
if ((nBytesErr = sutErr.available()) > 0)
{
if (nBytesErr > buffer.length)
{
buffer = null;
System.gc();
buffer = new byte[nBytesErr];
}
nBytesRead = sutErr.read(buffer, 0, nBytesErr);
if (nBytesRead == -1)
bStillRunning = false;
else
{
String sRep = new String(buffer,0,nBytesRead).replace("\n", "\r\n");
if (pOut != null)
{
pOut.print(sRep);
pOut.flush();
}
else
strOutput += sRep;
}
}
bStillRunning = (IsProcRunning(pProc) || (sutOut.available() > 0) || (sutErr.available() > 0));
}
catch (IOException e)
{
// Toast.makeText(SUTAgentAndroid.me.getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}
pProc.destroy();
buffer = null;
System.gc();
}
private boolean IsProcRunning(Process pProc)
{
boolean bRet = false;
@SuppressWarnings("unused")
int nExitCode = 0;
try
{
nExitCode = pProc.exitValue();
}
catch (IllegalThreadStateException z)
{
bRet = true;
}
return(bRet);
}
}

Просмотреть файл

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

Просмотреть файл

@ -0,0 +1,19 @@
package com.mozilla.watcher;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
// import android.os.Debug;
public class WatcherReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// Debug.waitForDebugger();
Intent serviceIntent = new Intent();
serviceIntent.putExtra("command", "start");
serviceIntent.setAction("com.mozilla.watcher.LISTENER_SERVICE");
context.startService(serviceIntent);
}
}

Просмотреть файл

@ -0,0 +1,914 @@
package com.mozilla.watcher;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.RemoteException;
import android.util.Log;
import android.view.Gravity;
import android.widget.Toast;
public class WatcherService extends Service
{
String sErrorPrefix = "##Installer Error## ";
String currentDir = "/";
String sPingTarget = "";
long lDelay = 60000;
long lPeriod = 300000;
int nMaxStrikes = 3;
Process pProc;
Context myContext = null;
Timer myTimer = null;
private PowerManager.WakeLock pwl = null;
public static final int NOTIFICATION_ID = 1964;
boolean bInstalling = false;
@SuppressWarnings("unchecked")
private static final Class[] mStartForegroundSignature = new Class[] {
int.class, Notification.class};
@SuppressWarnings("unchecked")
private static final Class[] mStopForegroundSignature = new Class[] {
boolean.class};
private NotificationManager mNM;
private Method mStartForeground;
private Method mStopForeground;
private Object[] mStartForegroundArgs = new Object[2];
private Object[] mStopForegroundArgs = new Object[1];
private IWatcherService.Stub stub = new IWatcherService.Stub() {
@Override
public int UpdateApplication(String sAppName, String sFileName, String sOutFile, int bReboot) throws RemoteException
{
return UpdtApp(sAppName, sFileName, sOutFile, bReboot);
}
};
@Override
public IBinder onBind(Intent arg0) {
return stub;
}
@Override
public void onCreate()
{
super.onCreate();
myContext = this;
getKeyGuardAndWakeLock();
File dir = getFilesDir();
File iniFile = new File(dir, "watcher.ini");
String sIniFile = iniFile.getAbsolutePath();
String sHold = "";
this.sPingTarget = GetIniData("watcher", "PingTarget", sIniFile, "www.mozilla.org");
sHold = GetIniData("watcher", "delay", sIniFile, "60000");
this.lDelay = Long.parseLong(sHold.trim());
sHold = GetIniData("watcher", "period", sIniFile,"300000");
this.lPeriod = Long.parseLong(sHold.trim());
sHold = GetIniData("watcher", "strikes", sIniFile,"3");
this.nMaxStrikes = Integer.parseInt(sHold.trim());
doToast("WatcherService created");
}
public String GetIniData(String sSection, String sKey, String sFile, String sDefault)
{
String sRet = sDefault;
String sComp = "";
String sLine = "";
boolean bFound = false;
BufferedReader in = null;
String sTmpFileName = fixFileName(sFile);
try {
in = new BufferedReader(new FileReader(sTmpFileName));
sComp = "[" + sSection + "]";
while ((sLine = in.readLine()) != null)
{
if (sLine.equalsIgnoreCase(sComp))
{
bFound = true;
break;
}
}
if (bFound)
{
sComp = (sKey + " =").toLowerCase();
while ((sLine = in.readLine()) != null)
{
if (sLine.toLowerCase().contains(sComp))
{
String [] temp = null;
temp = sLine.split("=");
if (temp != null)
{
if (temp.length > 1)
sRet = temp[1].trim();
}
break;
}
}
}
in.close();
}
catch (FileNotFoundException e)
{
sComp = e.toString();
}
catch (IOException e)
{
sComp = e.toString();
}
return (sRet);
}
private void handleCommand(Intent intent)
{
String sCmd = intent.getStringExtra("command");
// Debug.waitForDebugger();
if (sCmd != null)
{
if (sCmd.equalsIgnoreCase("updt"))
{
String sPkgName = intent.getStringExtra("pkgName");
String sPkgFile = intent.getStringExtra("pkgFile");
String sOutFile = intent.getStringExtra("outFile");
boolean bReboot = intent.getBooleanExtra("reboot", true);
int nReboot = bReboot ? 1 : 0;
SendNotification("WatcherService updating " + sPkgName + " using file " + sPkgFile, "WatcherService updating " + sPkgName + " using file " + sPkgFile);
UpdateApplication worker = new UpdateApplication(sPkgName, sPkgFile, sOutFile, nReboot);
}
else if (sCmd.equalsIgnoreCase("start"))
{
doToast("WatcherService started");
myTimer = new Timer();
myTimer.scheduleAtFixedRate(new MyTime(), lDelay, lPeriod);
}
else
{
doToast("WatcherService unknown command");
}
}
else
doToast("WatcherService created");
}
@Override
public void onStart(Intent intent, int startId) {
handleCommand(intent);
return;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
handleCommand(intent);
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
doToast("WatcherService destroyed");
if (pwl != null)
pwl.release();
stopForegroundCompat(R.string.foreground_service_started);
}
protected void getKeyGuardAndWakeLock()
{
// Fire off a thread to do some work that we shouldn't do directly in the UI thread
Thread t = new Thread() {
public void run() {
// Keep phone from locking or remove lock on screen
KeyguardManager km = (KeyguardManager)getSystemService(Context.KEYGUARD_SERVICE);
if (km != null)
{
KeyguardManager.KeyguardLock kl = km.newKeyguardLock("watcher");
if (kl != null)
kl.disableKeyguard();
}
// No sleeping on the job
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
if (pm != null)
{
pwl = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "watcher");
if (pwl != null)
pwl.acquire();
}
mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
try {
mStartForeground = getClass().getMethod("startForeground", mStartForegroundSignature);
mStopForeground = getClass().getMethod("stopForeground", mStopForegroundSignature);
}
catch (NoSuchMethodException e)
{
// Running on an older platform.
mStartForeground = mStopForeground = null;
}
Notification notification = new Notification();
startForegroundCompat(R.string.foreground_service_started, notification);
}
};
t.start();
}
/**
* This is a wrapper around the new startForeground method, using the older
* APIs if it is not available.
*/
void startForegroundCompat(int id, Notification notification) {
// If we have the new startForeground API, then use it.
if (mStartForeground != null) {
mStartForegroundArgs[0] = Integer.valueOf(id);
mStartForegroundArgs[1] = notification;
try {
mStartForeground.invoke(this, mStartForegroundArgs);
} catch (InvocationTargetException e) {
// Should not happen.
Log.w("ApiDemos", "Unable to invoke startForeground", e);
} catch (IllegalAccessException e) {
// Should not happen.
Log.w("ApiDemos", "Unable to invoke startForeground", e);
}
return;
}
// Fall back on the old API.
setForeground(true);
mNM.notify(id, notification);
}
/**
* This is a wrapper around the new stopForeground method, using the older
* APIs if it is not available.
*/
void stopForegroundCompat(int id) {
// If we have the new stopForeground API, then use it.
if (mStopForeground != null) {
mStopForegroundArgs[0] = Boolean.TRUE;
try {
mStopForeground.invoke(this, mStopForegroundArgs);
} catch (InvocationTargetException e) {
// Should not happen.
Log.w("ApiDemos", "Unable to invoke stopForeground", e);
} catch (IllegalAccessException e) {
// Should not happen.
Log.w("ApiDemos", "Unable to invoke stopForeground", e);
}
return;
}
// Fall back on the old API. Note to cancel BEFORE changing the
// foreground state, since we could be killed at that point.
mNM.cancel(id);
setForeground(false);
}
public void doToast(String sMsg)
{
Toast toast = Toast.makeText(this, sMsg, Toast.LENGTH_LONG);
toast.setGravity(Gravity.TOP|Gravity.CENTER_HORIZONTAL, 0, 100);
toast.show();
}
public void CheckMem() {
System.gc();
long lFreeMemory = Runtime.getRuntime().freeMemory();
long lTotMemory = Runtime.getRuntime().totalMemory();
long lMaxMemory = Runtime.getRuntime().maxMemory();
SendNotification("Memory Check", "Free: " + lFreeMemory + "Total: " + lTotMemory + "Max: " + lMaxMemory);
}
public int UpdtApp(String sPkgName, String sPkgFileName, String sOutFile, int bReboot)
{
int nRet = 1;
int lcv = 0;
String sRet = "";
// Debug.waitForDebugger();
FileOutputStream f = null;
try {
SendNotification("Killing " + sPkgName, "Step 1: Kill " + sPkgName + " if running");
while (!IsProcessDead(sPkgName) && (lcv < 5)) {
if (KillProcess(sPkgName, null).startsWith("Successfully"))
break;
else
lcv++;
Thread.sleep(2000);
}
CheckMem();
if ((sOutFile != null) && (sOutFile.length() > 0)) {
File outFile = new File(sOutFile);
if (outFile.exists() && outFile.canWrite()) {
f = new FileOutputStream(outFile, true);
} else {
SendNotification("File not found or cannot write to " + sOutFile, "File not found or cannot write to " + sOutFile);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
SendNotification("File not found " + sOutFile, "Couldn't open " + sOutFile + " " + e.getLocalizedMessage());
e.printStackTrace();
} catch (SecurityException e) {
SendNotification("Security excepetion for " + sOutFile, "Exception message " + e.getLocalizedMessage());
e.printStackTrace();
}
if ((sPkgName != null) && (sPkgName.length() > 0))
{
SendNotification("Uninstalling " + sPkgName, "Step 2: Uninstall " + sPkgName);
sRet = UnInstallApp(sPkgName, null);
CheckMem();
if ((sRet.length() > 0) && (f != null))
{
try {
f.write(sRet.getBytes());
f.flush();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
if ((sPkgFileName != null) && (sPkgFileName.length() > 0))
{
SendNotification("Installing " + sPkgFileName, "Step 3: Install " + sPkgFileName);
sRet = InstallApp(sPkgFileName, null);
SendNotification("Installed " + sPkgFileName, "" + sRet);
CheckMem();
if ((sRet.length() > 0) && (f != null))
{
try {
f.write(sRet.getBytes());
f.flush();
f.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
if (bReboot > 0)
RunReboot(null);
return(nRet);
}
public boolean GetProcessInfo(String sProcName)
{
boolean bRet = false;
ActivityManager aMgr = (ActivityManager) getApplicationContext().getSystemService(Activity.ACTIVITY_SERVICE);
List <ActivityManager.RunningAppProcessInfo> lProcesses = aMgr.getRunningAppProcesses();
int nProcs = lProcesses.size();
int lcv = 0;
String strProcName = "";
for (lcv = 0; lcv < nProcs; lcv++)
{
strProcName = lProcesses.get(lcv).processName;
if (strProcName.contains(sProcName))
{
bRet = true;
}
}
return (bRet);
}
public String RunReboot(OutputStream out)
{
String sRet = "";
String [] theArgs = new String [3];
theArgs[0] = "su";
theArgs[1] = "-c";
theArgs[2] = "reboot";
try
{
pProc = Runtime.getRuntime().exec(theArgs);
RedirOutputThread outThrd = new RedirOutputThread(pProc, out);
outThrd.start();
outThrd.join(10000);
}
catch (IOException e)
{
sRet = e.getMessage();
e.printStackTrace();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
return (sRet);
}
public String KillProcess(String sProcName, OutputStream out)
{
String [] theArgs = new String [3];
theArgs[0] = "su";
theArgs[1] = "-c";
theArgs[2] = "kill";
String sRet = sErrorPrefix + "Unable to kill " + sProcName + "\n";
ActivityManager aMgr = (ActivityManager) getSystemService(Activity.ACTIVITY_SERVICE);
List <ActivityManager.RunningAppProcessInfo> lProcesses = aMgr.getRunningAppProcesses();
int lcv = 0;
String strProcName = "";
int nPID = 0;
for (lcv = 0; lcv < lProcesses.size(); lcv++)
{
if (lProcesses.get(lcv).processName.contains(sProcName))
{
strProcName = lProcesses.get(lcv).processName;
nPID = lProcesses.get(lcv).pid;
sRet = sErrorPrefix + "Failed to kill " + nPID + " " + strProcName + "\n";
theArgs[2] += " " + nPID;
try
{
pProc = Runtime.getRuntime().exec(theArgs);
RedirOutputThread outThrd = new RedirOutputThread(pProc, out);
outThrd.start();
outThrd.join(5000);
}
catch (IOException e)
{
sRet = e.getMessage();
e.printStackTrace();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
// Give the messages a chance to be processed
try {
Thread.sleep(2000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
break;
}
}
if (nPID > 0)
{
sRet = "Successfully killed " + nPID + " " + strProcName + "\n";
lProcesses = aMgr.getRunningAppProcesses();
for (lcv = 0; lcv < lProcesses.size(); lcv++)
{
if (lProcesses.get(lcv).processName.contains(sProcName))
{
sRet = sErrorPrefix + "Unable to kill " + nPID + " " + strProcName + "\n";
break;
}
}
}
return (sRet);
}
public String GetAppRoot(String AppName)
{
String sRet = sErrorPrefix + " internal error [no context]";
Context ctx = getApplicationContext();
if (ctx != null)
{
try {
Context appCtx = ctx.createPackageContext(AppName, 0);
ContextWrapper appCtxW = new ContextWrapper(appCtx);
sRet = appCtxW.getPackageResourcePath();
appCtxW = null;
appCtx = null;
ctx = null;
System.gc();
}
catch (NameNotFoundException e)
{
e.printStackTrace();
}
}
return(sRet);
}
public boolean IsProcessDead(String sProcName)
{
boolean bRet = true;
ActivityManager aMgr = (ActivityManager) getSystemService(Activity.ACTIVITY_SERVICE);
List <ActivityManager.RunningAppProcessInfo> lProcesses = aMgr.getRunningAppProcesses(); // .getProcessesInErrorState();
int lcv = 0;
if (lProcesses != null)
{
for (lcv = 0; lcv < lProcesses.size(); lcv++)
{
if (lProcesses.get(lcv).processName.contentEquals(sProcName))
{
bRet = false;
break;
}
}
}
return (bRet);
}
public String fixFileName(String fileName)
{
String sRet = "";
String sTmpFileName = "";
sRet = fileName.replace('\\', '/');
if (sRet.startsWith("/"))
sTmpFileName = sRet;
else
sTmpFileName = currentDir + "/" + sRet;
sRet = sTmpFileName.replace('\\', '/');
sTmpFileName = sRet;
sRet = sTmpFileName.replace("//", "/");
return(sRet);
}
public String GetTmpDir()
{
String sRet = "";
Context ctx = getApplicationContext();
File dir = ctx.getFilesDir();
ctx = null;
try {
sRet = dir.getCanonicalPath();
}
catch (IOException e)
{
e.printStackTrace();
}
return(sRet);
}
public String UnInstallApp(String sApp, OutputStream out)
{
String sRet = "";
String [] theArgs = new String [3];
theArgs[0] = "su";
theArgs[1] = "-c";
theArgs[2] = "pm uninstall " + sApp + ";exit";
try
{
pProc = Runtime.getRuntime().exec(theArgs);
RedirOutputThread outThrd = new RedirOutputThread(pProc, out);
outThrd.start();
outThrd.join(60000);
int nRet = pProc.exitValue();
sRet = "\nuninst complete [" + nRet + "]";
}
catch (IOException e)
{
sRet = e.getMessage();
e.printStackTrace();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
return (sRet);
}
public String InstallApp(String sApp, OutputStream out)
{
String sRet = "";
String sHold = "";
String [] theArgs = new String [3];
theArgs[0] = "su";
theArgs[1] = "-c";
theArgs[2] = "pm install " + sApp + ";exit";
try
{
pProc = Runtime.getRuntime().exec(theArgs);
RedirOutputThread outThrd = new RedirOutputThread(pProc, out);
outThrd.start();
outThrd.join(180000);
int nRet = pProc.exitValue();
sRet += "\ninstall complete [" + nRet + "]";
sHold = outThrd.strOutput;
sRet += "\nSuccess";
}
catch (IOException e)
{
sRet = e.getMessage();
e.printStackTrace();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
return (sRet);
}
private String SendPing(String sIPAddr)
{
Process pProc;
String sRet = "";
String [] theArgs = new String [4];
boolean bStillRunning = true;
int nBytesOut = 0;
int nBytesErr = 0;
int nBytesRead = 0;
byte[] buffer = new byte[1024];
theArgs[0] = "ping";
theArgs[1] = "-c";
theArgs[2] = "3";
theArgs[3] = sIPAddr;
try
{
pProc = Runtime.getRuntime().exec(theArgs);
InputStream sutOut = pProc.getInputStream();
InputStream sutErr = pProc.getErrorStream();
while (bStillRunning)
{
try
{
if ((nBytesOut = sutOut.available()) > 0)
{
if (nBytesOut > buffer.length)
{
buffer = null;
System.gc();
buffer = new byte[nBytesOut];
}
nBytesRead = sutOut.read(buffer, 0, nBytesOut);
if (nBytesRead == -1)
bStillRunning = false;
else
{
String sRep = new String(buffer,0,nBytesRead).replace("\n", "\r\n");
sRet += sRep;
sRep = null;
}
}
if ((nBytesErr = sutErr.available()) > 0)
{
if (nBytesErr > buffer.length)
{
buffer = null;
System.gc();
buffer = new byte[nBytesErr];
}
nBytesRead = sutErr.read(buffer, 0, nBytesErr);
if (nBytesRead == -1)
bStillRunning = false;
else
{
String sRep = new String(buffer,0,nBytesRead).replace("\n", "\r\n");
sRet += sRep;
sRep = null;
}
}
bStillRunning = (IsProcRunning(pProc) || (sutOut.available() > 0) || (sutErr.available() > 0));
}
catch (IOException e)
{
e.printStackTrace();
}
if ((bStillRunning == true) && (nBytesErr == 0) && (nBytesOut == 0))
{
try {
Thread.sleep(2000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
pProc.destroy();
pProc = null;
}
catch (IOException e)
{
sRet = e.getMessage();
e.printStackTrace();
}
return (sRet);
}
private boolean IsProcRunning(Process pProc)
{
boolean bRet = false;
@SuppressWarnings("unused")
int nExitCode = 0;
try
{
nExitCode = pProc.exitValue();
}
catch (IllegalThreadStateException z)
{
bRet = true;
}
catch (Exception e)
{
e.printStackTrace();
}
return(bRet);
}
private class UpdateApplication implements Runnable {
Thread runner;
String msPkgName = "";
String msPkgFileName = "";
String msOutFile = "";
int mbReboot = 0;
public UpdateApplication(String sPkgName, String sPkgFileName, String sOutFile, int bReboot) {
runner = new Thread(this);
msPkgName = sPkgName;
msPkgFileName = sPkgFileName;
msOutFile = sOutFile;
mbReboot = bReboot;
runner.start();
}
@Override
public void run() {
bInstalling = true;
UpdtApp(msPkgName, msPkgFileName, msOutFile, mbReboot);
bInstalling = false;
}
}
private class MyTime extends TimerTask
{
int nStrikes = 0;
public MyTime()
{
}
@Override
public void run()
{
if (bInstalling)
return;
// See if the network is up, if not after three failures reboot
String sRet = SendPing(sPingTarget);
if (!sRet.contains("3 received"))
{
if (nMaxStrikes > 0)
{
if (++nStrikes >= nMaxStrikes)
RunReboot(null);
}
}
else
{
nStrikes = 0;
}
sRet = null;
String sProgramName = "com.mozilla.SUTAgentAndroid";
PackageManager pm = myContext.getPackageManager();
// Debug.waitForDebugger();
if (!GetProcessInfo(sProgramName))
{
Intent agentIntent = new Intent();
agentIntent.setPackage(sProgramName);
agentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
agentIntent.setAction(Intent.ACTION_MAIN);
try {
PackageInfo pi = pm.getPackageInfo(sProgramName, PackageManager.GET_ACTIVITIES | PackageManager.GET_INTENT_FILTERS);
ActivityInfo [] ai = pi.activities;
for (int i = 0; i < ai.length; i++)
{
ActivityInfo a = ai[i];
if (a.name.length() > 0)
{
agentIntent.setClassName(a.packageName, a.name);
break;
}
}
}
catch (NameNotFoundException e)
{
e.printStackTrace();
}
try
{
myContext.startActivity(agentIntent);
}
catch(ActivityNotFoundException anf)
{
anf.printStackTrace();
}
}
}
}
private void SendNotification(String tickerText, String expandedText) {
NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
int icon = R.drawable.ateamlogo;
long when = System.currentTimeMillis();
Notification notification = new Notification(icon, tickerText, when);
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notification.defaults |= Notification.DEFAULT_SOUND;
// notification.defaults |= Notification.DEFAULT_VIBRATE;
notification.defaults |= Notification.DEFAULT_LIGHTS;
Context context = getApplicationContext();
// Intent to launch an activity when the extended text is clicked
Intent intent = new Intent(this, WatcherService.class);
PendingIntent launchIntent = PendingIntent.getActivity(context, 0, intent, 0);
notification.setLatestEventInfo(context, tickerText, expandedText, launchIntent);
notificationManager.notify(NOTIFICATION_ID, notification);
}
private void CancelNotification() {
NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(NOTIFICATION_ID);
}
}

Просмотреть файл

@ -0,0 +1,11 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system use,
# "build.properties", and override values to adapt the script to your
# project structure.
# Project target.
target=android-5

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.5 KiB

Двоичные данные
build/mobile/sutagent/android/watcher/res/drawable-hdpi/icon.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 4.0 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.5 KiB

Двоичные данные
build/mobile/sutagent/android/watcher/res/drawable-ldpi/icon.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.7 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.5 KiB

Двоичные данные
build/mobile/sutagent/android/watcher/res/drawable-mdpi/icon.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.5 KiB

Просмотреть файл

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
</LinearLayout>

Просмотреть файл

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello World, WatcherMain!</string>
<string name="app_name">watcher</string>
<string name="foreground_service_started">Foreground Service Started</string>
</resources>

Просмотреть файл

@ -240,6 +240,9 @@ stage-mozmill: make-stage-dir
stage-android: make-stage-dir
$(NSINSTALL) $(DEPTH)/build/mobile/sutagent/android/sutAgentAndroid.apk $(PKG_STAGE)/bin
$(NSINSTALL) $(DEPTH)/build/mobile/sutagent/android/watcher/Watcher.apk $(PKG_STAGE)/bin
$(NSINSTALL) $(DEPTH)/build/mobile/sutagent/android/fencp/FenCP.apk $(PKG_STAGE)/bin
$(NSINSTALL) $(DEPTH)/build/mobile/sutagent/android/ffxcp/FfxCP.apk $(PKG_STAGE)/bin
stage-jetpack: make-stage-dir
$(NSINSTALL) $(topsrcdir)/testing/jetpack/jetpack-location.txt $(PKG_STAGE)/jetpack